Vue3 文档总结 - 高阶指南 - 响应性

高阶指南

响应式状态

  • reactive: 深层转化-用于转化对象,data 选项中返回的对象
  • ref 创建一个独立的响应式对象,通过 value 属性访问其内部值
  • ref 在模板中使用时,将会自动展开为原始值
  • 当 ref 存在于 reactive 参数对象中时,自动展开为原始值。reactive 的参数一定得是一个原始对象。不能是数组,或者 map 这种集合类型
 setup() {
     
    const myRef = ref(0)
    const myReactive = reactive({
     myRef})
    console.log(myReactive.myRef) // 0
    myReactive.myRef = 1
    console.log(myRef.value) // 1
  }
  • reactive 创建的响应式对象发生解构时,会丢失其响应式特性。解决方法是先通过 toRefs 转化为 一系列 Ref,再进行解构(toRef 是解构一个,需要两个参数,toRefs 处理一组。)
  • 使用 readonly 防止响应式对象的修改

响应式状态侦听、计算

computed

  • 计算属性 computed,接受一个函数(此时是 getter),也可以接受一个 包含 get 和 set 的对象参数。按照 Ref 的方式访问其值

watchEffect

  • watchEffect 在依赖变更时重新执行副作用。特点是立即执行,并且无需代入依赖参数。返回一个停止监听的函数
  setup() {
     
    const myRef = ref(0);
    onMounted(() => {
     
      setInterval(() => {
     
        myRef.value = myRef.value + 1;
      }, 1000);
    });
    const stopWatch = watchEffect(() => {
     
      console.log(myRef.value);
      if (myRef.value > 3) {
     
        stopWatch();
      }
    });
  • 但是 watchEffect 中如果是一个异步的副作用的话,就算我们通过返回函数去停止了监听,但是异步动作仍然是触发了的。所以需要一个函数,这个函数在 watchEffect 清除的同时,又能清除异步副作用。watchEffect 采用 onInvalidate 参数解决这个问题
  • ***onInvalidate 参数是为了在停止监听的时候,去除其未完成的副作用
  • ***类似于一个监听,监听到了停止事件,那么就会就会执行这个之前收集到的函数
  • ***通常在副作用执行之前,设置这个值
当没有设置 onInvalidate 监听函数的时候,到 4 停止。因为停止监听的时候,effect 已经执行
setup() {
     
   let timer = null;
   const data = ref(0);

   // 写一个异步的副作用
   const effect = () => {
     
     timer = setTimeout(() => {
     
       data.value = data.value + 1;
     }, 1000);
   };
   // 要在 data.value === 3时去停止监听,并且同时清除其由于状态已经改变而发生的副作用
   const stop = watchEffect((onInvalidate) => {
     
     effect();
     if (data.value === 3) {
     
       stop();
     }
   });
   return {
      data };
 },
当设置了 onInvalidate 监听,那么到 3 就会停止。在函数里写上清除副作用的函数
setup() {
     
    let timer = null;
    const data = ref(0);

    // 写一个异步的副作用
    const effect = () => {
     
      timer = setTimeout(() => {
     
        data.value = data.value + 1;
      }, 1000);
    };
    // 要在 data.value === 3时去停止监听,并且同时清除其由于状态已经改变而发生的副作用
    const stop = watchEffect((onInvalidate) => {
     
      onInvalidate(() => {
     
        clearTimeout(timer);
      });
      effect();

      if (data.value === 3) {
     
        stop();
      }
    });
    return {
      data };
  },
  • 当一个用户自定义的更新进入队列时,默认情况下会在 组件更新 之前执行。要想在组件更新之后执行一些副作用,可以代入一个带有 flush 选项的附加 options 对象(默认为‘pre’)
<template>
  <h1 v-for="item in data" :key="item">{
    { item }}h1>
template>
  setup() {
     
    const data = ref([]);
    const index = ref(0);
    onMounted(() => {
     
      setInterval(() => {
     
        index.value = index.value + 1;
        data.value[index.value] = index.value;
      }, 2000);
    });
    watchEffect(
      () => {
     
        const idx = index.value;
        const dom = document.getElementsByTagName("h1");
        console.log(dom[idx]); // 需配置{flush: 'post'}这里才可以获取到元素
      },

    );

    return {
      data };
  },
  • 侦听器调试:onTrack, onTrigger,都接受一个包含有关所依赖项信息的调试器事件。并且都只能在开发模式下工作
watchEffect(
  () => {
     
    const idx = index.value;
    const dom = document.getElementsByTagName("h1");
    console.log(dom[idx]);
  },
  {
     
    flush: "post",
    onTrack(e) {
     
      console.log(e.target.value);
    },
  }
);

watch

  • vue3 watch API 完全等同于 vue2 watch,写法和参数略有不同
  • watch 需要侦听特定数据源。在回调函数中执行副作用
  • watch 与 watchEffect 对比起来,watch 是惰性的
  • watch 侦听可以是函数形式的 reactive 的值,也可以是 ref,computed 等
  • watch 回调函数里可以直接拿到 ref 的原始值。
  • 监听 reactive 时,要在函数内返回要监听的值。回调函数的参数是监听的那个值,而不是整个 reactive 构造的 proxy
  • 与 watchEffect 共享停止侦听,清除副作用 (相应地 onInvalidate 会作为回调的第三个参数传入)、副作用刷新时机和侦听器调试行为
监听一个数据源
setup() {
     
    const index = ref(0);
    onMounted(() => {
     
      setInterval(() => {
     
        index.value = index.value + 1;
      }, 2000);
    });
    watch(index, (val, preVal) => {
     
      console.log("current", val); // 这里直接接收的是原始值

      console.log("pre value", preVal);
    });

    return {
      index };
  },
监听多个数据源
  setup() {
     
    const index = ref(0);
    const char = ref(100);
    onMounted(() => {
     
      setInterval(() => {
     
        index.value = index.value + 1;
        char.value--;
      }, 2000);
    });
    watch([index, char], ([index, char], [preIndex, preChar]) => {
     
      console.log("current index", index);
      console.log("current char", char);

      console.log("--------");
      console.log("pre index", preIndex);
      console.log("pre char", preChar);

      console.log("-------next loop--------------");

    });

    return {
      index, char };
监听 reactive
  setup() {
     
    const index = reactive({
     
      value: 0,
    });
    onMounted(() => {
     
      setInterval(() => {
     
        index.value = index.value + 1;
      }, 2000);
    });
    watch(
      () => index.value,
      (val, preVal) => {
     
        console.log("current index", val);
        console.log("pre index", preVal);

        console.log("-------next loop--------------");
      }
    );

    const {
      value } = toRefs(index);
    return {
      value };
  },
与 reactive 共享的行为(清除副作用为例)

  setup() {
     
    const index = reactive({
     
      value: 0,
    });
    let timer = null;

    const effect = () => {
     
      timer = setTimeout(() => {
     
        index.value = index.value + 1;
        console.log("interval", index.value);
      }, 1000);
    };
    effect(); // 需要自即调用一下触发惰性的 watch
    const stop = watch(
      () => index.value,
      (val, preVal, onInvalidate) => {
     
        onInvalidate(() => {
     
          clearTimeout(timer);
        });

        effect();

        if (val === 3) {
     
          stop();
        }
      }
    );

    const {
      value } = toRefs(index);
    return {
      value };
  },

你可能感兴趣的:(Vue3,vue)