🙈
【Vue3】リアクティブなオブジェクトをProvideする際の、プロパティアクセスには気をつけよう
一般的なリアクティブ値の分割代入アンチパターン
vue公式にもある通り、リアクティブなオブジェクトを分割代入しようとすると、オブジェクトのリアクティブ性が失われます。
import { reactive } from 'vue'
const book = reactive({
author: 'Vue',
title: 'Vue 3 Guide',
})
let { author, title } = book
リアクティブオブジェクトをProvideする際の、リアクティブ性を失うパターン
分割代入する以外にもリアクティブ性を失うパターンがあり、それは、プロパティアクセスした値をProvide関数にセットするです。
例えば、適当なリアクティブオブジェクトと、セッター関数を定義したsetup関数のあるコンポーネントがあるとします。
// Root.vue
const obj = reactive({
fuga: false,
foo: false,
})
const setHoge = () => {
hoge.fuga = true
hoge.foo = true
}
setHoge()
が実行されると、hogeオブジェクトの2つのプロパティの値が反転するようになっています。このコンポーネントをRoot
として、親子関係にない離れたコンポーネントへ値をProvieするとします。
ここで気をつけるのが先ほどお伝えした、プロパティアクセスした値をProvide関数にセットするです。
つまり、以下の書き方だとinjectした先のコンポーネントでは、リアクティブ性を失います。
// Root.vue
provide('fuga',obj.fuga); ❌
provide('foo',obj.foo); ❌
// Child.vue
const fuga = inject('fuga'); ❌
const foo = inject('foo'); ❌
console.log(obj.fuga) // false
console.log(obj.foo) // false
リアクティブ性を保つ書き方
provide側はオブジェクトを素直に渡して、inject側でそれぞれのプロパティにアクセスするようにしましょう。
// Root.vue
provide('obj',obj); ⭕️
// Child.vue
const obj = inject('obj'); ⭕️
console.log(obj.fuga) // true or false
console.log(obj.foo) // true or false
Discussion