vue3 ref和reactive踩坑
起因:开发时做一个列表状态筛选,遇到了数据更新但视图层没有更新的情况,把数据改为ref去操作即完成响应式数据的更新。
const hourRoomTableData = reactive([]}
if (val == '1') {
hourRoomTableData = hourRoomTableData.filter((item) => item.isEnable);
} else if (val == '2') {
hourRoomTableData = hourRoomTableData.filter((item) => !item.isEnable);
}
ref 和 reactive 是 Vue3 中实现响应式数据的核心 API。ref 用于包装基本数据类型,而 reactive 用于处理对象和数组。尽管 reactive 似乎更适合处理对象,但 Vue3 官方文档更推荐使用 ref。
1.ref
ref 是一个函数,它接受一个内部值并返回一个响应式且可变的引用对象。这个引用对象有一个 .value 属性,该属性指向内部值。
ref 支持深层响应性,这意味着它可以追踪和更新嵌套对象和数组中的变化。这种特性使得 ref 非常适合处理复杂的数据结构,如对象和数组。
ref 提供了高度的灵活性,尤其在处理「普通赋值」方面。这种灵活性使得 ref 在开发中的使用更加方便,特别是在进行复杂的数据操作时。
import { ref } from 'vue';
let state = ref({
count: 0,
name: 'Vue'
});
// 替换整个对象
state.value = {
count: 10,
name: 'Vue 4'
};
// 修改对象内的属性
state.value.count = 20;
state.value.name = 'Vue 5';
// 添加新的属性
state.value.newProperty = 'New Property';
// 删除属性
delete state.value.newProperty;
// 使用解构更新属性(注意要保持响应性)
let { count, name } = state.value;
state.value = { count: count + 1, name };
// 复杂操作,例如根据条件更新属性
if (someCondition) {
state.value = {
...state.value,
name: 'Updated Name'
};
}
console.log(state.value)
2.reactive
reactive 是一个函数,它接受一个对象并返回该对象的响应式代理,也就是 Proxy。
注意,ref核心是返回「响应式且可变的引用对象」,而reactive核心是返回的是「响应式代理」,这是两者本质上的核心区别,也就导致了ref优于reactive。
「直接赋值对象」:如果直接将一个响应式对象赋值给另一个变量,将会失去响应性。这是因为 reactive 返回的是对象本身,而不仅仅是代理。
import { reactive } from 'vue';
let state = reactive({ count: 0 });
state = { count: 1 }; // 失去响应性
「直接替换响应式对象」:同样,直接替换一个响应式对象也会导致失去响应性。
import { reactive } from 'vue';
let state = reactive({ count: 0 });
state = reactive({ count: 1 }); // 失去响应性
「直接解构对象」:在解构响应式对象时,如果直接解构对象属性,将会得到一个非响应式的变量。
const state = reactive({ count: 0 });
let { count } = state;
count++; // count 仍然是 0
解决这个问题,需要使用 toRefs 函数来将响应式对象转换为 ref 对象。
import { toRefs } from 'vue';
const state = reactive({ count: 0 });
let { count } = toRefs(state);
count++; // count 现在是 1
「将响应式对象的属性赋值给变量」:如果将响应式对象的属性赋值给一个变量,这个变量的值将不会是响应式的。
let state = reactive({ count: 0 })
let count = state.count
count++ // count 仍然是 0
console.log(state.count)