🫑

Vue.js を始めていちばん最初に知りたかった provide inject 機能を5年後に知った

2022/07/07に公開

親子関係

親子関係を Ruby で書くとこうなるのだけど、

class Parent
end

class Child
  def initialize(base)
    @base = base
  end
end

parent = Parent.new
child = Child.new(parent)

Vue.js もそれと同じでよかった。

世界中の人が使う汎用性の高いコンポーネントを作っているのではなく、自分だけが使うアプリのなかで、そこだけでしか使わないコンポーネントにぶら下がる、再利用など考える余地もない子コンポーネントに、親のポインタをそのまま渡せればよかった。

しかし、マニュアルを読んでも読んでも双方向データバインディングや $emit のことばかりだった。ググっても v-bind と $emit を駆使した必要最低限のデータリレーを正義とするような記事や、密結合にしたら死ぬんかよっていうようなコードで溢れ返っていた。

Vuex にも期待したが明後日の方を向いていた。

諦め

で、こりゃそもそも無理なんかもしれんなと調べるのを止めてしまった(反省)。そこで自力で捻り出したのがこれ。

Parent.vue
<template>
<Child :base="this" />
</template>

<script>
import Child from "./Child.vue"
export default {
  components: {
    Child,
  },
  data() {
    return {
      counter: 0,
    }
  },
}
</script>
Child.vue
<template>
<button @click="base.counter += 1">{{base.counter}}</button>
</template>

<script>
export default {
  props: ["base"],
}
</script>

こんな書き方をしていいのか? this とかビューの中で渡しちゃっていいのか? こんな書き方してる人見たことないぞ。誰かにバレたら袋叩きに遭うんじゃないか? と、不安を抱えながら5年間この方法で書いていた。

provide / inject

そして最近 provide と inject っていうのを知った。書き直すとこうなった。

Parent.vue
<template>
<Child />
</template>

<script>
import Child from "./Child.vue"
export default {
  components: {
    Child,
  },
  data() {
    return {
      counter: 0,
    }
  },
  provide() {
    return {
      base: this,
    }
  },
}
</script>
Child.vue
<template>
<button @click="base.counter += 1">{{base.counter}}</button>
</template>

<script>
export default {
  inject: ["base"],
}
</script>

それもっと早く知りたかった。

Discussion