vue3 watch笔记

 watchEffect

执行传入的一个函数,同时自动追踪函数中依赖到的数据,并在其依赖变更时重新运行该函数。
并且会在 组件挂载前 立即调用一次,(默认是挂载前,可通过修改 flush 属性改变,后边会讲到)
例子
复制代码
const person = reactive({
    count: 0,
});
onBeforeMount(() => {
    console.log("onBeforeMount");
});
onMounted(() => {
    console.log("onMounted");
});
watchEffect(
    () => {

        const el = document.querySelector(".h1");
        console.log(el);
        console.log(person.count);
    }
);
复制代码

 

 

停止监听器
调用返回值会停止监听,组件卸载时也会自动停止监听 (异步创建的监听器,组件卸载是不会自动停止监听的,需要手动调用,防止内存泄漏)
例子:
复制代码
const stop = watchEffect(
    () => {
        console.log(person.count);
    }
);
stop ()


// 注意!异步创建,组件卸载不会停止监听
setTimeout(() => {
  watchEffect(() => {})
}, 100)
 
复制代码

 

清除副作用
有时副作用函数会执行一些异步的副作用,需要在失效时清除(完成前状态已改变)。
可用调用 onInvalidate 函数。
副作用函数接收一个 onInvalidate 函数作为参数。 onInvalidate 接收一个回调函数。
第一次自调用 effect 副作用函数 是不会触发 onInvalidate 函数的,
触发 onInvalidate 函数有以下情况
依赖数据改变,再次调用 effect 副作用函数,
监听器被停止 (组件卸载前也会调用,因为组件卸载就会停止监听器)
例子
复制代码
watchEffect(
    (onInvalidate) => {
        onInvalidate(() => {
            console.log("before");
        });
        const el = document.querySelector(".h1");
        console.log(el);
        console.log(person.count);
    }
);
复制代码

第一次运行是不会触发

改变数据依赖时触发

 

 组件卸载前触发

 

 

 副作用刷新时机

vue 默认会缓存副作用函数,异步刷新,多个依赖数据同时改变也只会触发一次。并且会监听组件更新函数,在组件更新前去触发副作用函数。

可给 watchEffect 传递第二个参数,options 配置对象,改变 副作用函数触发时机,和执行次数。

options 配置对象中,flush 属性有三个值,'pre'、'post' 或 'sync'

pre :默认配置,组件挂载前 和 组件更新前 执行副作用函数,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数。

post : 组件挂载后 和 组件更新后 执行副作用函数,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数。

sync: 组件挂载前 和 组件更新前 执行副作用函数,不会缓存副作用函数,同步刷新,同时改变多个依赖数据会多次调用副作用函数。少用sync

默认配置,例子:

复制代码
const state = ref(0);
const person = reactive({
    count: 0,
});
const change2 = () => {
    state.value++;
    person.count++;
};
watchEffect(
    (onvalidate) => {
        onvalidate(() => {
            console.log("before");
        });
        const el = document.querySelector(".h1");
        console.log(el);
        console.log(person.count);
        console.log(state.value);
    }
);
复制代码

 

默认情况下 副作用函数会在 组件挂载前 和 组件更新前 执行,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数

 

 flush 属性值为 post,例子:

复制代码
watchEffect(
    (onvalidate) => {
        onvalidate(() => {
            console.log("before");
        });
        const el = document.querySelector(".h1");
        console.log(el);
        console.log(person.count);
        console.log(state.value);
    },
    {
        flush: "post"
    }
);
复制代码

在 组件挂载后,和 组件更新后 执行,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数

 

 

 flush 属性值为 sync,例子:

复制代码
watchEffect(
    (onvalidate) => {
        onvalidate(() => {
            console.log("before");
        });
        const el = document.querySelector(".h1");
        console.log(el);
        console.log(person.count);
        console.log(state.value);
    },
    {
        flush: "sync"
    }
);
复制代码

在 组件挂载前,和 组件更新前 执行,不会缓存副作用函数,同步刷新,同时改变多个依赖数据就多次调用副作用函数

 

监听器调试

监听器配置对象中,onTrack 和 onTrigger  选项可用于调试监听器行为(开发模式)

onTrack:会在响应式数据被追踪的时候被调用。(就是数据被获取时)

onTrigger: 响应式依赖改变时被调用 

例子

复制代码
const state = ref(0);
const person = reactive({
    count: 0,
});
const change2 = () => {
    state.value++;
    person.count++;
};
watchEffect(
    (onvalidate) => {
        onvalidate(() => {
            console.log("before");
        });
        const el = document.querySelector(".h1");
        console.log(el);
        console.log(state.value);
        console.log(person.count);
    },
    {
        onTrack(e) {
            console.log(e, "track");
        },
        onTrigger(e) {
            console.log(e, "trigger");
        },
    }
);
复制代码

第一次自动执行,获取响应式数据依赖,触发 onTrack

 

 

 改变依赖数据,触发 onTrigger

 

 

 

watch

监听特定的数据源,在回调函数中执行副作用,默认只有数据改变才会执行副作用函数, 不会立即调用副作用函数(可配置)

和 watchEffect 相比

  • 能访问监听数据变化前后值
  • 手动添加声明监听哪些数据
  • 也有 onInvalidate, 会作为回调函数的第三个参数,(注意,副作用函数第二次执行才会调用 onInvalidate)
  • 配置选项 flush 等.. watch 都有,多了 deep选项和 immediate 选项

监听单个数据源,例子

复制代码
const state = ref(0);
const person = reactive({
    count: 0,
});
const change2 = () => {
    state.value++;
    person.count++;
};
// 侦听一个 getter
watch(
    () => person.count,
    (count, prevCount) => {
        console.log(count, "count");
        console.log(prevCount, "prevCount");
    }
);

// 直接侦听ref
watch(state, (state, prevState) => {
    console.log(state, "count");
    console.log(prevState, "prevCount");
});
复制代码

 

 

 监听多个数据源,并且配置选项,例子

复制代码
const state = ref(0);
const person = reactive({
    count: 0,
});
const change2 = () => {
    state.value++;
    person.count++;
};
watch(
    [() => person.count, state],
    (arr, prevArr, onvalidate) => {
        console.log(arr, "arr");
        console.log(prevArr, "prevArr");
        onvalidate(() => {
            console.log("before");
        });
    },
    {
        immediate: true,
        flush: "pre",
        onTrigger(e) {
            console.log(e, "trigger");
        },
        onTrack(e) {
            console.log(e, "track");
        },
    }
);
复制代码

监听多个数据源用数组写法,回调函数参数1和2 也变成数组,配置选项 immediate 为 ture 时,初始化时会自执行一次副作用函数, 其它的配置项和 watchEffect 没区别

 

 

 

监听对象或数组,什么情况下配置 deep 选项

数据类型 直接监听 getter 写法 克隆数据,必须采用 getter 写法
ref 需要deep 需要deep 不需要deep
reactive 不需要deep 需要deep 不需要deep

 (注意,响应式数据为对象时直接监听,用的是同一个对象的引用,导致回调函数参数1和2,改变前后数据相同)。所以要克隆一个副本监听此副本,并使用 getter 写法。

例子:

复制代码
const person = ref({
    name: { Anna: { count: 0 } },
});
const person2 = reactive({
    name: { Anna: { count: 0 } },
});
const change2 = () => {
    person.value.name.Anna.count++;
    person2.name.Anna.count++;
};
// 直接监听 ref
watch(
    person,
    (person, prevPerson) => {
        console.log(person.name.Anna, "person");
        console.log(prevPerson.name.Anna, "prevPerson");
    },
    {
        deep: true,
    }
);
// 直接监听 reactive
watch(person2, (person, prevPerson) => {
    console.log(person.name.Anna, "person");
    console.log(prevPerson.name.Anna, "prevPerson");
});
// 监听reactive,getter 写法
watch(
    () => person2,
    (person, prevPerson) => {
        console.log(person.name.Anna, "person");
        console.log(prevPerson.name.Anna, "prevPerson");
    },
    {
        deep: true,
    }
);
复制代码

 

回调函数参数 1和2 出现数据相同 的问题

 

 

 

 

 

克隆响应式数据再监听,需要 getter 写法

复制代码
const person = reactive({
    name: { Anna: { count: 0 } },
});
const change2 = () => {
    person.name.Anna.count++;
};
watch(
    () => deepClone(person),
    (person, prevPerson) => {
        console.log(person.name.Anna, "person");
        console.log(prevPerson.name.Anna, "prevPerson");
    }
);
复制代码

现在 回调函数参数1和2,改变前后数据就正确了

 

 建议:响应式数据为对象或数组用watch监听时,用 getter 写法。

 

posted @   。吃什么  阅读(214)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示