一、ref 与 reactive 的选择依据
- 性能优化角度
- ref:适用于单个基本数据类型(如字符串、数字、布尔)或需要深度响应式的对象。当访问或修改 ref 数据时,会直接触发依赖更新。如果数据结构简单且更新频率高,使用 ref 可以减少不必要的代理开销。例如,一个计数器:
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
const increment = () => {
count.value++;
};
return {
count,
increment
};
}
};
- **reactive**:用于创建深度响应式的对象或数组。Vue 通过 Proxy 对整个对象进行代理,当对象内部属性变化时会触发响应式更新。对于复杂的对象结构且相对稳定的数据,reactive 更合适,因为它的代理机制能有效追踪对象内部的变化。例如,一个用户信息对象:
import { reactive } from 'vue';
export default {
setup() {
const user = reactive({
name: 'John',
age: 30,
address: {
city: 'New York'
}
});
const updateUser = () => {
user.age++;
};
return {
user,
updateUser
};
}
};
- 代码维护角度
- ref:语法简单,对于单个数据的操作一目了然,在代码中易于查找和理解。当数据逻辑独立且不依赖其他数据时,使用 ref 能使代码结构更清晰。
- reactive:对于复杂对象和数组,使用 reactive 能保持数据的整体性,在修改和维护对象内部结构时更方便。例如,管理一个商品列表,列表中的每个商品有多个属性,使用 reactive 声明商品列表对象更便于维护。
二、不同业务场景下的最佳实践
- 频繁更新的基本数据类型:使用 ref。如实时显示的系统时间:
import { ref, onMounted } from 'vue';
export default {
setup() {
const currentTime = ref('');
onMounted(() => {
const timer = setInterval(() => {
currentTime.value = new Date().toLocaleTimeString();
}, 1000);
return () => {
clearInterval(timer);
};
});
return {
currentTime
};
}
};
- 复杂且相对稳定的对象数据:使用 reactive。例如,一个电商购物车,包含多个商品项及其属性,购物车结构相对稳定但数据量较大:
import { reactive } from 'vue';
export default {
setup() {
const cart = reactive({
items: [
{ id: 1, name: 'Product 1', price: 10, quantity: 1 },
{ id: 2, name: 'Product 2', price: 20, quantity: 2 }
],
totalPrice: 0
});
const updateTotalPrice = () => {
cart.totalPrice = cart.items.reduce((acc, item) => acc + item.price * item.quantity, 0);
};
return {
cart,
updateTotalPrice
};
}
};
三、可能遇到的性能问题及解决方法
- 不必要的重新渲染
- 问题:当 reactive 对象中的某个属性变化时,可能会导致整个组件重新渲染,即使其他属性未改变,从而影响性能。
- 解决方法:使用
computed
计算属性,它会缓存依赖数据,只有依赖数据变化时才重新计算。例如,在上述购物车例子中,totalPrice
可以定义为计算属性:
import { reactive, computed } from 'vue';
export default {
setup() {
const cart = reactive({
items: [
{ id: 1, name: 'Product 1', price: 10, quantity: 1 },
{ id: 2, name: 'Product 2', price: 20, quantity: 2 }
]
});
const totalPrice = computed(() => {
return cart.items.reduce((acc, item) => acc + item.price * item.quantity, 0);
});
return {
cart,
totalPrice
};
}
};
- 深度嵌套对象更新问题
- 问题:在深度嵌套的 reactive 对象中,直接修改深层属性可能不会触发响应式更新。
- 解决方法:使用 Vue 提供的
set
方法(Vue 2.x)或通过解构重新赋值(Vue 3.x)。例如,在上述用户信息对象中,如果要更新 address.city
:
import { reactive } from 'vue';
export default {
setup() {
const user = reactive({
name: 'John',
age: 30,
address: {
city: 'New York'
}
});
const updateCity = () => {
// Vue 3.x 方式
user.address = {
...user.address,
city: 'Los Angeles'
};
};
return {
user,
updateCity
};
}
};
- 大量数据渲染性能问题
- 问题:当有大量数据需要渲染时,即使使用了合理的响应式声明,渲染性能仍可能受影响。
- 解决方法:采用虚拟滚动技术,如
vue - virtual - scroll - list
插件,只渲染可见区域的数据,减少 DOM 操作和内存占用。