Vueでのprovide/injectの応用について
5051 ワード
周知のように,コンポーネント式開発において,最大の痛みはコンポーネント間の通信にある.Vueでは、基本的なprops/$emitから兄弟コンポーネント通信用のEventBus、グローバルデータ管理用のVuexまで、さまざまなコンポーネント通信方式が提供される.
このような多くのコンポーネント通信方式ではprovide/injectは非常にアカリンに見える(存在感がない).しかし、provide/injectにもその活躍の場がある.今日は、Vueのprovide/injectの応用についてお話しします.
Provide/injectとは
Provide/injectはVueが2.2.0バージョンで追加したAPIで、公式サイトでは以下のように紹介されています.
このオプションは、コンポーネント階層がどれだけ深く、上下関係が成立した時間内に常に有効になるかにかかわらず、祖先コンポーネントがすべての子孫子孫に依存を注入できるように、一緒に使用する必要があります.Reactに詳しい場合は、Reactのコンテキスト特性に似ています.
公式サイトの解釈はとても人を困惑させて、それでは私はこのいくつかの言叶を訳します:
Provideは、祖先コンポーネントで子孫コンポーネントに提供したいデータまたはメソッドを指定できますが、どの子孫コンポーネントでもinjectを使用してprovideが提供したデータまたはメソッドを受信できます.
公式サイトを挙げます.
親コンポーネントが提供するfoo変数は、コンポーネントが正常に受信され、使用されていることがわかります.
Provide/injectが何であるかを理解したら、provide/injectを使用します.
provide/injectを使用したグローバルステータス管理
日常の开発の中で、私达はいつもVuexを使って状态の管理をして、しかし、私个人はずっとVuexを使うのが好きではありませんて、原因はVuexが状态を维持するために追迹されることができて、使うのが面倒すぎるためです;私が以前参加したプロジェクトは、多くの人が協力していませんでした.この機能は私にとって、意味がありません.私はVuexでグローバルな状態を提供する機能だけが必要です.
では、グローバルな状態を簡単かつ迅速に実現する方法はありますか?もちろんありますが、これがprovide/injectというブラックテクノロジーAPIの使い方です.
ルートコンポーネントで変数を入力し、子孫コンポーネントで使用する方法を考える人が多いかもしれません.
この考えは、正しいと言っても正しいし、間違っても間違っていない.原因はprovideの特殊性にある.
公式サイトのドキュメントでprovide/injectについて次のようなヒントがあります.
ヒント:
すなわち,Vueはprovide中の変数を応答的に処理しない.したがって,injectが受け入れる変数が応答式であるためにはprovideが提供する変数自体が応答式である必要がある.
コンポーネント内部の様々な状態が応答可能であるため,我々は直接ルートコンポーネントにコンポーネント自体をprovideに注入するが,この場合,子孫コンポーネントの中でルートコンポーネントのすべての状態に任意にアクセスでき,ルートコンポーネントはグローバル状態のコンテナとなり,Reactのcontextに似ているのではないかとよく考える.
コードは次のとおりです.
$rootを使用してルートノードを取得できる場合、provide/injectを使用する必要はありません.
実際の開発では、1つのプロジェクトに複数の人が開発することが多く、一人一人が異なるグローバル変数を必要とする可能性があります.すべての人のグローバル変数がルートコンポーネントに統一的に定義されている場合、変数の衝突などの問題が発生します.
Provide/injectの異なるモジュールのエントリコンポーネントを使用して、それぞれの子孫コンポーネントに渡すことで、この問題を完璧に解決できます.
Provide/injectの使用を慎む
provide/injectがこんなに使いやすい以上、なぜVue公式は原生のAPIではなくVuexを使うことをお勧めしますか?
前述したように、Vuexとprovide/injectの最大の違いは、Vuexのグローバル状態の変更のたびに遡及を追跡できることであり、provide/injectの変数の変更は制御できません.言い換えれば、どのコンポーネントがこのグローバル状態を変更したのか分かりません.
Veeの設計理念はReactにおける一方向データストリームの原則(syncのような一方向データストリームを破壊するやつがいるが)を参考にしているが,provide/injectは一方向データストリームの原則を明らかに破壊している.複数の子孫コンポーネントが1つの祖先コンポーネントが提供するステータスに同時に依存している場合、1つのコンポーネントがステータスを変更すると、すべてのコンポーネントが影響を受けます.この態様は結合度を増加させ,一方,データの変化を制御できないようにした.複数の人が協力して開発すれば、悪夢になるだろう.
ここではprovide/injectを用いたグローバルステータス管理の原則を2つまとめました.複数人が協力する場合、役割ドメイン隔離 を行う.は、できるだけ一括データをグローバル状態 として使用する.
Provide/injectを使ってグローバルステータス管理をするのは危険そうですが、provide/injectの方が良い使い方はありますか?もちろんあります.それはprovide/injectを使用してコンポーネントを作成することです.
Provide/injectを使用してコンポーネントを記述する
Provide/injectを使用したコンポーネント開発は、Vueの公式ドキュメントで提唱されている方法です.
私がよく知っているelementUIを例に挙げます.
elementUIにはButton(ボタン)コンポーネントがあり、Form(フォーム)コンポーネントで使用すると、そのサイズは外層のFormItemコンポーネントと、より外層のFormコンポーネントのsizeプロパティの両方に影響されます.
通常のシナリオであれば、propsを使用してFormから属性値を階層的に渡すことができます.2層を渡すだけでいいように見えますが、納得できます.しかし、Formの次のコンポーネントは必ずしもFormItemではなく、FormItemの次のコンポーネントはButtonではなく、他のコンポーネントをネストすることもできます.つまり、階層関係が不確定です.propsを使用すると、私たちが書いたコンポーネントが強く結合する場合があります.
Provide/injectはこの問題を完璧に解決することができ、コンポーネント自体(コンテキスト)を子孫に注入するだけで、子孫コンポーネントでは階層を無視して祖先コンポーネントの状態に任意にアクセスすることができる.
ソースの一部は次のとおりです.
まとめ
実はVueの学習の中で、二八の法則に従って、私たちがよく使う20%のAPIは大部分の日常の問題を解決することができて、残りのAPIはあまり役に立たないと感じます.しかし、時間を割いてそれらの冷たいAPIを理解して、あなたはいくつかの普通ではない風景を発見することができて、あなたにいくつかの問題を解決する時、仕事が半分で倍になります.
このような多くのコンポーネント通信方式ではprovide/injectは非常にアカリンに見える(存在感がない).しかし、provide/injectにもその活躍の場がある.今日は、Vueのprovide/injectの応用についてお話しします.
Provide/injectとは
Provide/injectはVueが2.2.0バージョンで追加したAPIで、公式サイトでは以下のように紹介されています.
このオプションは、コンポーネント階層がどれだけ深く、上下関係が成立した時間内に常に有効になるかにかかわらず、祖先コンポーネントがすべての子孫子孫に依存を注入できるように、一緒に使用する必要があります.Reactに詳しい場合は、Reactのコンテキスト特性に似ています.
公式サイトの解釈はとても人を困惑させて、それでは私はこのいくつかの言叶を訳します:
Provideは、祖先コンポーネントで子孫コンポーネントに提供したいデータまたはメソッドを指定できますが、どの子孫コンポーネントでもinjectを使用してprovideが提供したデータまたはメソッドを受信できます.
公式サイトを挙げます.
// 'foo'
var Provider = {
provide: {
foo: 'bar'
},
// ...
}
// 'foo'
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
// ...
}
親コンポーネントが提供するfoo変数は、コンポーネントが正常に受信され、使用されていることがわかります.
Provide/injectが何であるかを理解したら、provide/injectを使用します.
provide/injectを使用したグローバルステータス管理
日常の开発の中で、私达はいつもVuexを使って状态の管理をして、しかし、私个人はずっとVuexを使うのが好きではありませんて、原因はVuexが状态を维持するために追迹されることができて、使うのが面倒すぎるためです;私が以前参加したプロジェクトは、多くの人が協力していませんでした.この機能は私にとって、意味がありません.私はVuexでグローバルな状態を提供する機能だけが必要です.
では、グローバルな状態を簡単かつ迅速に実現する方法はありますか?もちろんありますが、これがprovide/injectというブラックテクノロジーAPIの使い方です.
ルートコンポーネントで変数を入力し、子孫コンポーネントで使用する方法を考える人が多いかもしれません.
//
export default {
provide () {
return {
text: 'bar'
}
}
}
// 'app'
{{this.text}}
export default {
inject: ['text'],
created() {
this.text = 'baz' // , 'bar'
}
}
この考えは、正しいと言っても正しいし、間違っても間違っていない.原因はprovideの特殊性にある.
公式サイトのドキュメントでprovide/injectについて次のようなヒントがあります.
ヒント:
provide
およびinject
バインディングは応答可能ではありません.これはわざとやったのだ.しかし、リスニング可能なオブジェクトが送信された場合、そのオブジェクトのプロパティは応答可能です.すなわち,Vueはprovide中の変数を応答的に処理しない.したがって,injectが受け入れる変数が応答式であるためにはprovideが提供する変数自体が応答式である必要がある.
コンポーネント内部の様々な状態が応答可能であるため,我々は直接ルートコンポーネントにコンポーネント自体をprovideに注入するが,この場合,子孫コンポーネントの中でルートコンポーネントのすべての状態に任意にアクセスでき,ルートコンポーネントはグローバル状態のコンテナとなり,Reactのcontextに似ているのではないかとよく考える.
コードは次のとおりです.
//
export default {
provide () {
return {
app: this
}
},
data () {
return {
text: 'bar'
}
}
}
// 'app'
{{this.app.text}}
export default {
inject: ['app'],
created() {
this.app.text = 'baz' // , 'baz'
}
}
$rootを使用してルートノードを取得できる場合、provide/injectを使用する必要はありません.
実際の開発では、1つのプロジェクトに複数の人が開発することが多く、一人一人が異なるグローバル変数を必要とする可能性があります.すべての人のグローバル変数がルートコンポーネントに統一的に定義されている場合、変数の衝突などの問題が発生します.
Provide/injectの異なるモジュールのエントリコンポーネントを使用して、それぞれの子孫コンポーネントに渡すことで、この問題を完璧に解決できます.
Provide/injectの使用を慎む
provide/injectがこんなに使いやすい以上、なぜVue公式は原生のAPIではなくVuexを使うことをお勧めしますか?
前述したように、Vuexとprovide/injectの最大の違いは、Vuexのグローバル状態の変更のたびに遡及を追跡できることであり、provide/injectの変数の変更は制御できません.言い換えれば、どのコンポーネントがこのグローバル状態を変更したのか分かりません.
Veeの設計理念はReactにおける一方向データストリームの原則(syncのような一方向データストリームを破壊するやつがいるが)を参考にしているが,provide/injectは一方向データストリームの原則を明らかに破壊している.複数の子孫コンポーネントが1つの祖先コンポーネントが提供するステータスに同時に依存している場合、1つのコンポーネントがステータスを変更すると、すべてのコンポーネントが影響を受けます.この態様は結合度を増加させ,一方,データの変化を制御できないようにした.複数の人が協力して開発すれば、悪夢になるだろう.
ここではprovide/injectを用いたグローバルステータス管理の原則を2つまとめました.
Provide/injectを使ってグローバルステータス管理をするのは危険そうですが、provide/injectの方が良い使い方はありますか?もちろんあります.それはprovide/injectを使用してコンポーネントを作成することです.
Provide/injectを使用してコンポーネントを記述する
Provide/injectを使用したコンポーネント開発は、Vueの公式ドキュメントで提唱されている方法です.
私がよく知っているelementUIを例に挙げます.
elementUIにはButton(ボタン)コンポーネントがあり、Form(フォーム)コンポーネントで使用すると、そのサイズは外層のFormItemコンポーネントと、より外層のFormコンポーネントのsizeプロパティの両方に影響されます.
通常のシナリオであれば、propsを使用してFormから属性値を階層的に渡すことができます.2層を渡すだけでいいように見えますが、納得できます.しかし、Formの次のコンポーネントは必ずしもFormItemではなく、FormItemの次のコンポーネントはButtonではなく、他のコンポーネントをネストすることもできます.つまり、階層関係が不確定です.propsを使用すると、私たちが書いたコンポーネントが強く結合する場合があります.
Provide/injectはこの問題を完璧に解決することができ、コンポーネント自体(コンテキスト)を子孫に注入するだけで、子孫コンポーネントでは階層を無視して祖先コンポーネントの状態に任意にアクセスすることができる.
ソースの一部は次のとおりです.
// Button
export default {
name: 'ElButton',
// inject elForm elFormItem
inject: {
elForm: {
default: ''
},
elFormItem: {
default: ''
}
},
// ...
computed: {
_elFormItemSize() {
return (this.elFormItem || {}).elFormItemSize;
},
buttonSize() {
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
},
//...
},
// ...
};
まとめ
実はVueの学習の中で、二八の法則に従って、私たちがよく使う20%のAPIは大部分の日常の問題を解決することができて、残りのAPIはあまり役に立たないと感じます.しかし、時間を割いてそれらの冷たいAPIを理解して、あなたはいくつかの普通ではない風景を発見することができて、あなたにいくつかの問題を解決する時、仕事が半分で倍になります.