1.功能
侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
// 1.属性
const state = reactive({
count: 0 })
watch(
() => state.count,
(count, prevCount) => {
}
)
// 2.数组
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
})
// 3.getter 函数 需要使用 { deep: true } 强制侦听器进入深层级模式
const state = reactive({
count: 0 })
watch(
() => state,
(newValue, oldValue) => {
// newValue === oldValue 由于返回的是对象引用地址相同
},
{
deep: true }
)
// 4.响应式数据 默认开启深度监听
const state = reactive({
count: 0 })
watch(state, () => {
/* 深层级变更状态所触发的回调 */
})
2.原理
watch
是一个ReactiveEffect
,把接收的getter
函数或对象或数组都转化为getter
函数形式,回调方法相当于scheduler
3.实现
// 递归取值 收集effect
function traverse(source, s = new Set()) {
if (!isObject(source)) {
return source;
}
if (s.has(source)) {
return source;
}
s.add(source);
for (const key in source) {
traverse(source[key], s);
}
return source;
}
export function watch(source, cb, options) {
// 如果source是个对象,需要遍历 通过reactive的is_reactive判断
let getter;
if (isReactive(source)) {
// 无论是对象还是函数都处理成函数,需要遍历,默认做深度处理 需要让每个属性都收集watch
getter = traverse(source); //深度遍历
} else if (isFunction(source)) {
getter = source;
}
const job = () => {
let newValue = effect.run();
cb(newValue, oldValue);
oldValue = newValue;
};
let oldValue;
const effect = new ReactiveEffect(getter, job);
if (options.immediate) {
job();
}
oldValue = effect.run();
}
cleanup实现
let i = 2000;
function getData(timer){
return new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(timer)
}, timer);
})
}
watch(()=>state.age,async (newValue,oldValue,onCleanup)=>{
let clear = false;
onCleanup(()=>{
clear = true;
})
i-=1000;
let r = await getData(i); // 第一次执行1s后渲染1000, 第二次执行0s后渲染0, 最终应该是0
if(!clear){
document.body.innerHTML = r;}
},{
flush:'sync'});
state.age = 31;
state.age = 32;
let cleanup;
let onCleanup = (fn) =>{
cleanup = fn;
}
const job = () =>{
const newValue = effect.run();
if(cleanup) cleanup(); // 下次watch执行前调用上次注册的回调
cb(newValue,oldValue,onCleanup); // 传入onCleanup函数
oldValue = newValue
}