**`computed` 本质是一种基于依赖的计算缓存。**
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
思考一个问题:这个和普通的getter和setter有什么区别?为什么需要单独封装一个`computed` ?
export const ComputedExample03 = defineComponent({
setup() {
const count = ref(1)
const plusOne = {
get value() {
return count.value + 1
},
}
return () => {
return <div>{plusOne.value}<button onClick={() => count.value ++}>+</button></div>
}
},
})
上面例子中触发`onClick` 可以使得组件刷新
`computed` 提供的是对计算的封装,让封装计算更容易。
export const ComputedExample01 = defineComponent({
setup: () => {
const msg = ref("hello")
const reversedMsg = computed(() => {
return msg.value.split("").reverse().join("")
})
return () => {
return <div>
<input onInput={(e) => {
msg.value = (e.target as HTMLInputElement).value
}} />
{reversedMsg.value}
</div>
}
},
})
具体的computed的定义:
function computed<T>(
getter: () => T,
debuggerOptions?: DebuggerOptions
): Readonly<Ref<Readonly<T>>>
当然上面的程序可以这样写,而不用computed:
export const ComputedExample02 = defineComponent({
setup: () => {
const msg = ref("hello")
const reversedMsg = (msg : string) => {
return msg.split("").reverse().join("")
}
return () => {
return <div>
<input onInput={(e) => {
msg.value = (e.target as HTMLInputElement).value
}} />
{reversedMsg(msg.value)}
</div>
}
},
})
保留个人观点:个人认为第二种方案语义更加清晰,因为第二种语义从语法上可以知道这是一次reversedMsg的计算。
最后, `computed` 和使用一个函数进行计算,有一个最本质的区别:
- computed会根据依赖重算
- 提供了基于依赖的缓存
例如下面程序中的`get` 只会触发一次,因为没有依赖的reactive值。
export const ComputedExample04 = defineComponent({
setup() {
let val = 1
const someVal = computed({
get: () => {
console.log('run...')
return val
},
set : () => {
val++
}
})
return () => {
return (
<div>
{someVal.value}
<button onClick={() => {
someVal.value ++
}}>next</button>
</div>
)
}
},
})
1