前言
在 Vue.js 中,响应式的核心是将数据和函数关联起来。简单来说,当我们使用 Vue.js 的 template
时,它实际上是一个 render
函数,这个函数依赖于响应式数据。当数据发生变化时,这个 render
函数会重新运行,从而更新视图。
但要注意,并不是所有函数都能自动关联到数据。在 Vue.js@2 中,是通过 watcher
监控函数,在 Vue.js@3 中,使用的是 effect
,比如 render
、computed
、watchEffect
和 watch
。
另外,并不是所有数据都可以被关联。只有那些定义为响应式的数据,并且在函数中被使用,才能建立这种关联。
第一个案例
<script setup>
const props = defineProps({
count: Number,
});
const doubleCount = ref(props.count * 2);
</script>
在这个例子中,doubleCount
是通过 props.count
初始化的。但是,点击按钮后,doubleCount
不会变化。这是因为 doubleCount
只是初始化时依赖了 props.count
,是一个原始值,而没有在之后的过程中与 props.count
关联。
简单来说,数据与数据之间并没有自动建立起关联,这在 JavaScript 中是无法实现的,那么 Vue.js 也就无法实现。
第二个案例
<script setup>
const doubleCount = ref(0);
watchEffect(() => {
doubleCount.value = props.count * 2;
});
</script>
这里,我们使用了 watchEffect
。当你点击按钮时,UI 上的 doubleCount
会跟着变化。这是因为 watchEffect
的回调函数会被 watchEffect
监控,而这个回调函数中使用了响应式的 props.count
。所以,watchEffect
会跟踪 props.count
的变化,并在数据改变时重新执行回调函数,从而更新 doubleCount
,最后重新调用 render
函数渲染视图。
第三个案例
<script setup>
function useDouble(count) {
const doubleCount = ref(count * 2);
watchEffect(() => {
doubleCount.value = count * 2;
});
return doubleCount;
}
const doubleCount = useDouble(props.count);
</script>
在这个例子中,useDouble
函数返回了一个 doubleCount
。但是,点击按钮后,doubleCount
不会更新。
这是因为 count
传入 useDouble
时也是原始值,而不是响应式数据。watchEffect
只会在函数内部监控 count
的变化,但这里 count
只是一个普通的数字,没有响应式能力。因此,doubleCount
不会随着 props.count
的变化而更新,render
函数也不会重新调用。
第四个案例
const doubleCount = computed(() => props.count * 2);
这里,我们使用了 computed
。computed
属性可以根据 props.count
自动更新。当 props.count
变化时,computed
中的函数也会重新运行,从而更新 doubleCount
。由于 template
依赖了 doubleCount
,所以 render
函数会被重新调用,视图也会随之更新。
第五个案例
function useDouble(count) {
const doubleCount = computed(() => count * 2);
return doubleCount;
}
const doubleCount = useDouble(props.count);
在这个例子中,useDouble
函数返回了一个 computed
属性。由于传递给 useDouble
的 count
仍然是原始值,computed
也不会自动跟踪 props.count
的变化。要确保 doubleCount
更新,我们需要确保 count
是响应式的。
解决
要让 doubleCount
随着 props.count
的变化而更新,你可以使用 computed
属性,或者添加一个 watch
来监控 props.count
的变化,并更新 doubleCount
。示例代码:
const doubleCount = ref(props.count * 2);
watch(() => props.count, (doubleCount.value = props.count * 2));