vue3源码(四)watch

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
}

相关推荐

  1. vue3watch

    2024-01-31 11:54:02       48 阅读
  2. vue2解析---watch和computed

    2024-01-31 11:54:02       62 阅读
  3. Vue3 watch侦听器

    2024-01-31 11:54:02       45 阅读
  4. VUE3——watch函数

    2024-01-31 11:54:02       37 阅读
  5. 学习 Vue 3

    2024-01-31 11:54:02       66 阅读
  6. vue3中的watch

    2024-01-31 11:54:02       58 阅读
  7. vue3watch详解

    2024-01-31 11:54:02       42 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-31 11:54:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-31 11:54:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-01-31 11:54:02       87 阅读
  4. Python语言-面向对象

    2024-01-31 11:54:02       96 阅读

热门阅读

  1. raft实现心得-核心设计

    2024-01-31 11:54:02       55 阅读
  2. mapper xml中 <和>的写法

    2024-01-31 11:54:02       53 阅读
  3. 瑞芯微1808模型转换(onnx到rknn)环境配置过程

    2024-01-31 11:54:02       63 阅读
  4. ES客户端接入方式

    2024-01-31 11:54:02       43 阅读
  5. 2024.1.22 parse_rule.用户画像es数据使用rule规则读取

    2024-01-31 11:54:02       45 阅读
  6. wrappedComponentRef和ref的区别

    2024-01-31 11:54:02       52 阅读
  7. 通过MediaStore查询image,video,arm,pdf等等文件数据

    2024-01-31 11:54:02       49 阅读
  8. Spring-yml

    2024-01-31 11:54:02       50 阅读
  9. C# 策略模式(Strategy)

    2024-01-31 11:54:02       48 阅读