2021-09-15に更新

refとshallowRefが実際どう違うのかわからなかったので確認

// 普通のref
const normal = ref({name: 'Tama'})
const normalName = computed(() => `normalRef.value.name: ${normal.value.name}`)
console.log('①', normalName.value); // ① normalRef.value.name: Tama

// shallowRef
const shallow = shallowRef({name: 'Tama'})
const shallowName = computed(() => `shallowRef.value.name: ${shallow.value.name}`)
console.log('②', shallowName.value); // ② shallowRef.value.name: Tama

// オブジェクト内部の値を変更すると...
normal.value.name = 'Mike'
// reactiveなのでcomputedが再計算される
console.log('③', normalName.value); // ③ normalRef.value.name: Mike

// オブジェクト内部の値を変更しても...
shallow.value.name = 'Mike'
// reactiveではないのでcomputedは再計算されない
console.log('④', shallowName.value); // ④ shallowRef.value.name: Tama

動作の違い

ref()は引数がオブジェクトだった場合に内部でreactiveを呼び出してる(つまり、最初からreactive()で作った場合と同じ)。一方shallowRef()は引数のオブジェクトをリアクティブ変換せずにそのまま保持している。

上の例ではref, shallowRefのオブジェクト内のnameプロパティを変更している。
refではリアクティブなのでcmputedが再計算されるが、shllowRefではされない。

実際問題になるケース

  • shallowRefにオブジェクトを渡して、かつその中身に依存したcomputedwatchを書く場合には注意。上の例みたいに変更検知ができなくなる。
  • プリミティブの場合はどっちを使ってもまったく同じ
  • オブジェクトを渡すけど、中身にはタッチしない(オブジェクトそのものが変わった時だけ検知できれば良い)なら、性能的な観点でshallowRefを使った方がよさそう
  • refによるリアクティブ化は再帰的に実行されるので、オブジェクトの構造が深くて大きいとパフォーマンスに影響するかも。この場合にもshallowRef

後で調べる

テンプレートrefの場合ってどうなってるの?DOM要素が入ってるはずだけどこれも再帰的にreactive化されてる?shallowRefでもいいの?


yuneco
コメント