watchAPI 与选项式 API this.$watch (以及相应的 watch 选项) 完全等效。watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用。默认情况下,它也是惰性的——即回调仅在侦听源发生变化时被调用。

  • 与 watchEffect 相比,watch 允许我们:

    • 惰性地执行副作用;
    • 更具体地说明应触发侦听器重新运行的状态;
    • 访问被侦听状态的先前值和当前值。

API:

watch(WatcherSource, Callback, [WatchOptions])

interface WatchOptions extends WatchEffectOptions {
  immediate?: boolean // 默认:false
  deep?: boolean
}

watch单个源: 

setup() {
  const showNav = ref(true);
  watch(
    showNav,
    () => {
      const [search] = document.getElementsByClassName('search');
      if (search) search.style.height = !showNav.value ? '100%' : 'calc(100% - 0.7rem)';
    },
    { immediate: true },
  );
}

watch多个源:

import { useStore } from 'vuex';
import { ref } from 'vue';

setup() {
  const store = useStore();

  const showNav = ref(true);
  const user = JSON.parse(window.localStorage.getItem('user') || null);

  watch(
    [showNav, user],
    ([sNVal, uNVal]) => {
      const [search] = document.getElementsByClassName('search');
      if (search) search.style.height = !sNVal.value ? '100%' : 'calc(100% - 0.7rem)';

      if (uNVal && Object.keys(uNVal).length) {
        setInterval(() => {
          store.dispatch('announce/notification');
        }, 6000);
      }
    },
    { immediate: true },
  );
}

 

在 setup 中 watch props 的某个属性:

export default {
  props: {
    partParams: [Object]
  },
  setup (props) {
    /** resAPI */
    function getDictionaryInfoByCon ({ dicName, dicType }) {
      const payload = {
        dicName,
        dicType,
        page: pageContain.page,
        rows: pageContain.rows
      };

      fetchDictionaryInfoByCon(payload).then(({ data: resData }) => {
        const { status, obj, total } = resData;

        if (status === 200) {
          const info = obj.map((i, index) => ({ key: index, dicId: i.dicId, dicName: i.dicName, dicType: i.dicType, dicKey: i.dicKey, dicValue: i.dicValue, dicSymbol: i.dicSymbol }));

          preDataSource.value = Object.assign([], info);
          dataSource.value = Object.assign([], info);

          pageContain.total = total;
        }
      });
    }

    /**  focal point  */
    watch(() => props.partParams, (newVal) => {
      getDictionaryInfoByCon({ dicName: newVal.dicName, dicType: newVal.dicType });
    }, { immediate: true });
  }
}

 

监听数组变化 :

  1. 将数组定义为响应式数据ref时,如果不加上deep:true,watch是监听不到值的变化的。
  2. 将数组定义为响应式数据ref,加上deep:true,watch可以检测到数据的变化,但老值和新值一样,即不能获取老值。
  3. 将数组定义为响应式对象时,不作任何处理,watch可以检测到数据的变化,但老值和新值一样。
  4. 将数组定义为响应式对象时,把watch的数据源写成函数的形式并通过扩展运算符克隆一份数组返回,可以在监听的同时获得新值和老值。

最佳实践:watch的数据源写成函数的形式并通过扩展运算符克隆一份数组返回,在监听的同时获得新值和老值。

setup() {
    const testArr = ref([]);

    const pushTest = (val) => {
      testArr.value.push(val);
    }

    const popTest = () => {
      testArr.value.pop();
    }

    /** 数组监听的实践- ref, 且加上deep: true */
    watch(testArr, (newVal) => {
      console.log('newVal', newVal);
    }, { deep: true });

    return { testArr, pushTest, popTest }
  },
setup() {
    const testArr = reactive([]);

    const pushTest = (val) => {
      testArr.push(val);
    }

    const popTest = () => {
      testArr.pop();
    }

    /** 数组监听的最佳实践- reactive且源采用函数式返回,返回拷贝后的数据 */
    watch(() => [...testArr], (newVal, oldVal) => {
      console.log('newVal', newVal);
      console.log('oldVal', oldVal);
    });
    
    return { testArr, pushTest, popTest }
  },

 

 监听对象变化:

  1. 把对象定义为响应式对象reactive时,采用函数形式的返回,如果不加上deep:true,watch是监听不到值的变化的。
  2. 把对象定义为响应式对象reactive时,加上deep:true,watch可以检测到数据的变化,但老值和新值一样,即不能获取老值。
  3. 把watch的数据源写成函数的形式并通过深拷贝克隆(这里用了lodash库的深拷贝)一份对象返回,在监听的同时获得新值和老值。

最佳实践:把数据定义成响应式对象reactive,把watch的数据源写成函数的形式并通过深拷贝克隆一份对象返回,在监听的同时获得新值和老值。

<script>
import { reactive, watch } from 'vue';
import _ from 'lodash';

export default {
  name: 'TestDemo',
  setup () {
    const objReactive = reactive({user: {name: 'aa', age: '18'}, brand: 'Channel'});
    
    /** 对象深度监听的最佳实践- reactive且源采用函数式返回,返回深拷贝后的数据 */
    watch(() => _.cloneDeep(objReactive), (newVal, oldVal) => {
      console.log('newVal', newVal);
      console.log('oldVal', oldVal);
    })
  }
}
</script>

参考文献:

Computed 与 watch | Vue.js

Vue3中watch的最佳实践 - 掘金

vue3的Watch监听事件的使用 - 掘金

Logo

前往低代码交流专区

更多推荐