toRef()的Vue官方定义
基于响应式对象上的一个属性,创建一个对应的ref。这样创建的ref与其源属性保持同步:改变源属性的值将更新ref的值,反之亦然。
官方基础示例
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
// 更改该 ref 会更新源属性
fooRef.value++
console.log(state.foo) // 2
// 更改源属性也会更新该 ref
state.foo++
console.log(fooRef.value) // 3
PS:
const fooRef = ref(state.foo)
该ref不会与state.foo保持同步。
问题的出现
结合以上,在页面上的展现可得如下结论:
- toRef 如果原始对象是非响应式的,数据会变,但视图不会更新;
- 原始对象用reactive包裹,再使用toRef,点击按钮则看到视图和数据都变了;
- toRef返回的值是否具有响应性取决于被解构的对象本身是否具有响应性。
然而,当一个组件内同时存在原始对象和reactive对象的toRef值时,数据和视图均变化。 代码如下:
import { reactive, toRef, watch, watchEffect, onMounted, onBeforeUpdate } from 'vue';
// toRef 如果原始对象是非响应式的,数据会变,但视图不会更新
const obj = {
name: '李白',
age: 32
}
// 当我们把obj1用reactive包裹,再使用toRef,点击按钮则看到视图和数据都变了
// toRef返回的值是否具有响应性取决于被解构的对象本身是否具有响应性。
const obj1 = reactive({
name: '杜甫',
age: 46
})
const state = toRef(obj, 'age');
const state1 = toRef(obj1, 'age');
const change = () => {
state.value++;
state1.value++;
console.log('obj:', obj,'state:', state);
}
watch(state, () => {
console.log('state change---'); // 当只有state时不会触发该watch
})
watch(state1, () => {
console.log('state1 change---')
})
watchEffect(() => {
console.log('watchEffect---obj.age', obj.age);
console.log('watchEffect---obj1.age', obj1.age);
console.log('watchEffect---state.age', state.value)
console.log('watchEffect---state1.age', state1.value)
})
onMounted(() => {
console.log('component mounted---');
})
onBeforeUpdate(() => {
console.log('onBeforeUpdate----'); // 当只有state时不会触发该watch
})
当change函数执行时,
由此可见,原始对象的toRef值不具有响应式,变动时不能更新视图,但有其他的响应式数据更新时会触发页面的刷新,从而刷新视图。
在vue-devtool内可以看到,state和state1均为ref是有点展示问题的,手动修改state值页面不会刷新,而state1则正常。
所以,响应式数据的更新会触发页面更新,带动非响应式数据的被动视图更新。
toRefs的vue官方定义
toRefs 将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的ref。每个单独的ref都是使用toRef()创建的。
const state = reactive({
foo: 1,
bar: 2
})
const state1 = toRefs(state); // 经toRefs解析过的state分解成两个单独的ref值,但是单独的state1却不是一个ref或者reactive
const judge = () => {
console.log('state1 is ref?:', isRef(state1)); // false
console.log('state1 is reactive?:', isReactive(state1)); // false
}
const change = () => {
state.foo++;
state1.bar.value++;
}
watch(state, () => {
console.log('state change---');
})
watch(state1.bar, () => { // 这里直接侦听state1是无效的
console.log('state1.bar change---')
})
watchEffect(() => {
console.log('watchEffect---state.foo', state.foo)
console.log('watchEffect---state1.bar', state1.bar.value)
})
onMounted(() => {
console.log('component mounted---');
})
onBeforeUpdate(() => {
console.log('onBeforeUpdate----')
})