🌚

provide / inject でリアクティブにするなら単にレシーバーを受け渡した方がいい

2023/03/14に公開
問題のコード
<div id="app">
  <button @click="count += 1">{{count}}</button>
  <c1></c1>
  <c2></c2>
</div>

<script defer src="https://unpkg.com/vue@2"></script>
<script type="module">
  new Vue({
    el: "#app",
    components: {
      c1: {
        inject: ["count"],
        template: "<div>c1:{{count}}</div>",
      },
      c2: {
        inject: ["app"],
        template: "<div>c2:{{app.count}}</div>",
      },
    },
    provide() {
      return {
        count: this.count,
        app: this,
      }
    },
    data() {
      return {
        count: 0,
      }
    },
  })
</script>

親で count をインクリメントしたとき、

  • c1
    • 表示は 0 のまま
    • 描画されていないだけでなく this.count 自体に何の変化もない
  • c2
    • 同期している
    • 親と同じものを見ている

となってめっちゃはまるのでリアクティブになんかなってくれなくていいという特殊な状況でない限りはレシーバーを受け渡した方いい。

上の例では count のレシーバーが this なので this を渡した。もし foo: { count: 0 } のデータ定義であれば foo を渡せば一応リアクティブにはなる。ただしデータ構造を変えただけでリアクティブにならなくなる危うさを抱えているので全部 this でいい。

Vue 3 でも同様にはまるのかはわからない。

Discussion