梗概

  • 如果一个computed返回引用类型,先判断新旧值有没有变化,一样就返回旧的值
    • 防止新旧两个对象内的属性值都相同,但实际是两个不同的对象,导致computed重新计算

原理

从 3.4 开始,计算属性仅在其计算值较前一个值发生更改时才会触发副作用。

例如,以下 isEven 计算属性仅在返回值从 true 更改为 false 时才会触发副作用,反之亦然:

const count = ref(0)
const isEven = computed(() => count.value % 2 === 0)
watchEffect(() => console.log(isEven.value)) // true
// 这将不会触发新的输出,因为计算属性的值依然为 `true`
count.value = 2
count.value = 4

这减少了非必要副作用的触发。但不幸的是,如果计算属性在每次计算时都创建一个新对象,则不起作用:

const computedObj = computed(() => {
  return {
    isEven: count.value % 2 === 0
  }
})

由于每次都会创建一个新对象,因此从技术上讲,新旧值始终不同。即使 isEven 属性保持不变,Vue 也无法知道,除非它对旧值和新值进行深度比较。这种比较可能代价高昂,并不值得。 相反,我们可以通过手动比较新旧值来优化。如果我们知道没有变化,则有条件地返回旧值:

const computedObj = computed((oldValue) => {
  const newValue = {
    isEven: count.value % 2 === 0
  }
  if (oldValue && oldValue.isEven === newValue.isEven) {
    return oldValue
  }
  return newValue
})