Vue 3 避坑指南(二):watchEffect 用法建议
本文通过一个路由和变量绑定的案例介绍 watchEffect
的使用技巧、限制和注意事项。我们将知道应当在数据就绪后再参与监听,watch
比 watchEffect
高级应当始终使用 watch
即可。
案例:将路由绑定到响应式变量
现在说一个简化的需求,假设我们有三个变量:author
、committer
、merger
,它们的 id 作为 URL 的 query 参数实时更新。那么,我们首先在代码中定义这三个响应式样变量:
1 | const author = ref(null) |
然后,组件初始挂载时通过路由参数获取到变量的值:
1 | onMounted(async () => { |
现在要求 author
、committer
、merger
三个变量改变时,对应的 URL 也能变更。这时可以用到 watchEffect
:
1 | watchEffect(() => { |
问题一:应在数据就绪后再监听
如果 watchEffect
写到 onMounted
外面,则初始化时 author.value
、committer.value
、merger.value
都是 null
,则上述函数执行时会出错。(即使不出错,一开始时地址栏就会根据三个 null
值被替换,这也是不对的)。因此,watchEffect
应放在 onMounted
内部,即在数据初始化后再执行。
1 | onMounted(async () => { |
问题二:watchEffect
会立即执行
watchEffect
因为它的机制问题,需要立即执行一遍以得到响应式依赖。但上述监听立即执行会得到一个问题,就是 router.replace
会重复加载已经存在的 URL. 虽然不会出现什么大问题,但控制台会给出一个警告,说明此时 watchEffect
立即执行还是有问题的,应该等待 author
、committer
、merger
其中一个变量有更新时才应当执行。
watch
默认是延迟执行的,换成 watch
就能解决:
1 | watch([author, committer, merger], () => { |
总结
我们使用 watchEffect
是为了让系统自动帮我们计算依赖,但它有个立即执行的限制,在使用时应当注意。如果使用场景中要求我们延迟执行,此时就要换成 watch
,并把依赖包装成数组作为监听变量。
不论是使用 watch
还是 watchEffect
,都要记住一点,应当在数据就绪后才开始监听。我们要知道监听的依赖以及它们当前所处的状态,是加载好的还是一个未知的状态。因为这个原因,watchEffect
自动计算依赖的特性似乎就缺少了吸引力,我们要时刻关注到监听的依赖以及它们的当前状态。因此,现实场景中只使用 watch
就好,它还能决定是立即执行还是延迟执行。