searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

watch详解

2024-06-11 08:55:06
1
0

当在数据变化后,我们想要执行一系列副作用选择使用watch函数

watch(() => obj.a, (newVal, oldVal) => {
    // 执行一系列操作
}, {deep: true} )
 

但是深层监听时候会对监听对象做深度遍历所以对象属性繁多复杂,开销较大,降低性能。

具体监听策略通过阅读源码,具体如下所示

 

源码分析

主要针对watchgetter函数进行剖析接收到deep深度监听,对监听对象做了traverse深度优先遍历

 

深度优先遍历算法如下所示

function traverse(value, depth = Infinity, seen) {
  // 递归出口
  if (depth <= 0 || !shared.isObject(value) || value["__v_skip"]) {
    return value;
  }
  seen = seen || /* @__PURE__ */ new Set();
  if (seen.has(value)) {
    return value;
  }
  seen.add(value);
  depth--;
  // 针对每个数据类型做不同遍历处理
  if (reactivity.isRef(value)) {
    traverse(value.value, depth, seen);
  } else if (shared.isArray(value)) {
    for (let i = 0; i < value.length; i++) {
      traverse(value[i], depth, seen);
    }
  } else if (shared.isSet(value) || shared.isMap(value)) {
    value.forEach((v) => {
      traverse(v, depth, seen);
    });
  } else if (shared.isPlainObject(value)) {
    for (const key in value) {
      traverse(value[key], depth, seen);
    }
  }
  return value;
}
 

watch除deep外,还有多个配置选项

1.  immediate监听器创建立即触发回调

2.  flush回调函数触发时机pre:dom更新前调用postdom更新调用sync同步调用

3.  onTrack/onTrigger调试钩子依赖收集回调函数触发调用

4.  once回调只在变化触发一次

 

watchEffect

watch监听对象较多书写逻辑比较复杂可以利用watchEffect降低代码复杂度同时watchEffect自动追踪响应式数据变化

watchEffect(() => {
    console.log(obj.a)
})
 

我们希望dom更新后执行watch回调可以利用watchPostEffect函数

watchPostEffect(() => {
    console.log('更新dom节点后的值:', obj.a)
})

同样,如果针对具体业务场景,可以直接对源码打业务补丁,对watch进行具体应用场景的watch封装

0条评论
0 / 1000
w****n
17文章数
1粉丝数
w****n
17 文章 | 1 粉丝
原创

watch详解

2024-06-11 08:55:06
1
0

当在数据变化后,我们想要执行一系列副作用选择使用watch函数

watch(() => obj.a, (newVal, oldVal) => {
    // 执行一系列操作
}, {deep: true} )
 

但是深层监听时候会对监听对象做深度遍历所以对象属性繁多复杂,开销较大,降低性能。

具体监听策略通过阅读源码,具体如下所示

 

源码分析

主要针对watchgetter函数进行剖析接收到deep深度监听,对监听对象做了traverse深度优先遍历

 

深度优先遍历算法如下所示

function traverse(value, depth = Infinity, seen) {
  // 递归出口
  if (depth <= 0 || !shared.isObject(value) || value["__v_skip"]) {
    return value;
  }
  seen = seen || /* @__PURE__ */ new Set();
  if (seen.has(value)) {
    return value;
  }
  seen.add(value);
  depth--;
  // 针对每个数据类型做不同遍历处理
  if (reactivity.isRef(value)) {
    traverse(value.value, depth, seen);
  } else if (shared.isArray(value)) {
    for (let i = 0; i < value.length; i++) {
      traverse(value[i], depth, seen);
    }
  } else if (shared.isSet(value) || shared.isMap(value)) {
    value.forEach((v) => {
      traverse(v, depth, seen);
    });
  } else if (shared.isPlainObject(value)) {
    for (const key in value) {
      traverse(value[key], depth, seen);
    }
  }
  return value;
}
 

watch除deep外,还有多个配置选项

1.  immediate监听器创建立即触发回调

2.  flush回调函数触发时机pre:dom更新前调用postdom更新调用sync同步调用

3.  onTrack/onTrigger调试钩子依赖收集回调函数触发调用

4.  once回调只在变化触发一次

 

watchEffect

watch监听对象较多书写逻辑比较复杂可以利用watchEffect降低代码复杂度同时watchEffect自动追踪响应式数据变化

watchEffect(() => {
    console.log(obj.a)
})
 

我们希望dom更新后执行watch回调可以利用watchPostEffect函数

watchPostEffect(() => {
    console.log('更新dom节点后的值:', obj.a)
})

同样,如果针对具体业务场景,可以直接对源码打业务补丁,对watch进行具体应用场景的watch封装

文章来自个人专栏
Vue前端开发
17 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0