Vue3のcomputedパフォーマンス考察
こういう状況のときに、
const map = ref<{ [key:string]: number }>({ a: 1, b: 2 })
const keys = computed(() => Object.keys(map.value))
こうすると、keys
は再評価される。
map.value = { a: 1, b: 2 }
こうすると、keys
は再評価されない。
map.value.b = 3
hooksでもこう書いたら結果は同様。
const keys = useMemo(() => Object.keys(map), [map])
こう書いたら再評価は回避できる?できる気がする
(実際は算出関数がもっと複雑かつkeysにだけ依存しているとして)
const keys = useMemo(() => Object.keys(map), [Object.keys(map)])
compositionで同様な再評価タイミングを実現させるにはキャッシュ用の状態をもってwatch
を使うしかないか?
中身に興味はないけどキー一覧を使って重い算出をしたいような状況。
const keys = ref<string[]>([])
watch(() => Object.keys(map.value), () => {
return Object.keys(map.value)
})
vue3って書いたけど多分このあたりの挙動はvue2から変わってないと思われる。
computed
に無意味なデフォルト値を返させたい場合、primitiveでない場合は常にundefined
を返すようにしたほうがよい。
if (~~) return {}
という風にその場で空objektを返してしまうと、そのcomputed
はdirtyと見なされて後続がすべて再評価されていく。
undefined
判定が増えてしまうがそれを補ってパフォーマンスが向上する。
このwatch
の書き方ではObject.keys(map.value)
に変化がなくてもコールバックは実行されてしまうっぽかった。Object.keys(map.value).sort().join(',')
とかにしてもだめ。
評価の関数はcomputed
と同じく参照の更新を見ているのかもしれない(戻り値はcallbackへ渡すために必要なだけか?)。
onBeforeUpdate
を使って自力で値を評価しないとだめそう。
let keys = ''
onBeforeUpdate(() => {
const nextKeys = Object.keys(map.value).sort().join(',')
if (keys !== nextKeys) {
~~ callback ~~
keys = nextKeys
}
})
onBeforeUpdate
の中でref
等を変更しても再度onBeforeUpdate
が実行されることはないっぽい。
provide
、inject
を使うと、それを参照しない中間コンポーネントの再評価をスキップできる。
props
で受け渡していくと中間コンポーネントも再評価される。
v-memoという新たなdirectiveが3.2から導入された。
<template>
内でしか使えないがProxy
式ではなく値で評価してくれる。