[Vue3] reactive、ref、shallowReactive 和 shallowRef 的区别
reactive
reactive
函数的返回了一个 Proxy 代理对象,添加 set 和 get 拦截,把 track
和 trigger
两个函数加入进来。
file:[reactive 伪代码]
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key)
return target[key]
},
set(target, key, value) {
target[key] = value
trigger(target, key)
}
})
}
如果传递的对象有多层嵌套,那就需要递归创建,否则就没有 Proxy 去代理嵌套对象,实现响应式。
也就是说,对象嵌套得越多,递归的次数就越多,但这种消耗根据文档的意思来说,不是特别大。若要创建不递归的响应式对象,通过 shallowReactive
或 shallowRef
来创建。
shallowRef
shallowRef
不主动更新视图,需要通过 triggerRef
。或者,强制性替换原对象的值让视图更新。
file:[src/App.vue]
let state = shallowRef({
foo: {
bar: 1
},
foobar: 2
});
function changeState() {
// 自加不会触发页面更新
state.value.foo.bar++;
state.value.foobar++;
// 替换 state.value 的根对象页面才会更新
const replace = {
foo: {
bar: state.value.foo.bar
},
foobar: state.value.foobar
};
state.value = replace;
}
推荐通过 triggerRef
更新视图。
file:[src/App.vue]
function triggerUpdate() {
state.value.foo.bar++;
state.value.foobar++;
triggerRef(state);
}
ref 和 reactive
ref
得到一个对象类型(Map、Object 等)时,是通过 reactive
创建的响应式数据。所以,遇到对象类型,可以直接用 reactive
。
或者,统一都用 ref
创建响应式数据。
shallowRef 场景
如果你希望修改数据的时候视图不立即更新,可通过 shallowRef
来实现,在需要的时候通过 triggeRef
来更新视图。
如上图所示,当我展开表格编辑时,这些输入框会导致视图立即更新,界面重新渲染,导致打开的界面被关闭。
表格的数据是由 ref
创建,是深层次响应式数据。所以,shallowRef
创建的浅层响应式数据可能会让界面的发生变化,但至少不会重新渲染界面。