🙈

【Vue3】リアクティブなオブジェクトをProvideする際の、プロパティアクセスには気をつけよう

2022/05/24に公開

一般的なリアクティブ値の分割代入アンチパターン

vue公式にもある通り、リアクティブなオブジェクトを分割代入しようとすると、オブジェクトのリアクティブ性が失われます。

import { reactive } from 'vue'

const book = reactive({
  author: 'Vue',
  title: 'Vue 3 Guide',
})

let { author, title } = book

https://v3.ja.vuejs.org/guide/reactivity-fundamentals.html#リアクティブな状態の分割代入

リアクティブオブジェクトを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

参考: https://zenn.dev/azukiazusa/articles/ref-vs-article

Discussion