Vueの中のprovide/injectの応用について詳しく説明します。

5334 ワード

コンポーネント開発において、最大の痛みはコンポーネント間の通信にあることが知られている。Vueでは、Vueは様々なコンポーネント通信方式を提供しており、基本的なprops/emitから兄弟コンポーネント通信用のEventBusにかけて、グローバルデータ管理用のVuexに至る。
このように多くのコンポーネント通信方式では、provide/injectは非常にAca林に見える(存在感がない)。しかし、provide/injectにも彼らの活躍の場があります。今日はVueの中のプロヴィッド/injectの応用について話しましょう。
provide/injectとは?
provide/injectはVueの2.2.0バージョンで追加されたAPIです。公式サイトでは以下のように紹介されています。
このオプションは、コンポーネントの階層がどれほど深いかに関わらず、祖先のコンポーネントがその子孫の子孫に一つの依存性を注入することを可能にするために一緒に使用され、上下関係が成立するまでの時間にわたって常に有効である。Reactに詳しいなら、これはReactの文脈特性と似ています。
公式サイトの説明はとても疑問です。
プロヴィッドは、先祖のコンポーネントの中で、私たちが後代のコンポーネントに提供したいデータまたは方法を指定することができますが、どのような後代のコンポーネントでも、provideが提供するデータまたは方法を受信するためにinjectを使用することができます。
公式サイトのを挙げます🌰:

//        '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を使用することが好きではありません。以前参加したプロジェクトは多くの人と協力していません。この機能は私にとってあまり意味がありません。
では、早く全体の状態を実現する方法がありますか?もちろんあります。これはprovide/injectというブラックテクノロジーAPIの使い方です。
多くの人が考えているかもしれません。ルート・コンポーネントの中に、変数が入ってきて、次の世代のコンポーネントで使えばいいです。

//                   
export default {
 provide () {
  return {
   text: 'bar'
  }
 }
}

//        'app'
<template>
 <div>{{this.text}}</div>
</template>
<script>
 export default {
  inject: ['text'],
  created() {
   this.text = 'baz' //     ,     'bar'
  }
 }
</script>

この考えは正しいと言ってもいいです。正しくないと言っても間違っていません。理由はプロヴィッドの特殊性にあります。
公式文書ではprovide/injectについてこんなヒントがあります。
ヒント:provideとinjectのバインディングは応答できません。これは故意にやったのです。しかし、傍受可能なオブジェクトが入ってきたら、オブジェクトの属性はまだ応答可能です。
つまり、Vueはprovideの変数に応答しないということです。したがって、injectが受け取る変数は応答式であり、provideが提供する変数自体は応答式である必要があります。
コンポーネントの内部の様々な状態が応答できるので、直接にルートのコンポーネント自体をプロvideに注入します。この時、私達は次の世代のコンポーネントの中で任意のルートのコンポーネントの中のすべての状態にアクセスできます。ルートのコンポーネントは大域状態の容器になります。よく考えてみると、Reactの中のcontextに似ていますか?
コードは以下の通りです

//                
export default {
 provide () {
  return {
   app: this
  }
 },
 data () {
  return {
   text: 'bar'
  }
 }
}

//        'app'
<template>
 <div>{{this.app.text}}</div>
</template>
<script>
 export default {
  inject: ['app'],
  created() {
   this.app.text = 'baz' //     ,   'baz'
  }
 }
</script> 

ある学生が聞きましたが、米ドルを使ってもルートノードが取れます。私達はprovide/injectを使う必要がありますか?
実際の開発では、一つのプロジェクトは多くの人が開発しています。一人一人が異なるグローバル変数を必要とする可能性があります。
変数の衝突などの問題が起こるのは必至です。
provide/injectの異なるモジュールの入口コンポーネントを使用して、それぞれの后代コンポーネントに送ることで、この問題を完璧に解決することができます。
provide/injectを慎む
プロヴィッド/injectがこんなに使いやすいなら、なぜVue公式は私達にVuexを使うように勧めますか?
前述したように、Vuexとprovide/injectの最大の違いは、Vuexにおけるグローバル状態の修正は追跡可能であり、provide/injectにおける変数の修正は制御不能であり、言い換えれば、どのコンポーネントがこのグローバル状態を修正したのか分かりません。
Vueの設計理念はReactの一方向データフローの原則を参考にしていますが、provide/injectは一方向データストリームの原則を著しく破壊しています。考えてみると、複数のサブアセンブリが同時に一つの祖先のコンポーネントから提供された状態に依存している場合、一つのコンポーネントがこの状態を修正すると、すべてのコンポーネントが影響を受ける。この態様は結合度を増加させ,一方ではデータの変化を制御できないようにした。多くの人が協力して開発すれば、悪夢になります。
ここでは、provide/injectを使ってグローバル状態管理をする二つの条の原則をまとめました。
  • 人以上の人が協力する時、役割ドメイン分離をしっかりと行います。
  • は、グローバル状態
  • として1回限りのデータを使用する。
    provide/injectを使って全体の状態管理をするのは危険そうですが、provide/injectのより良い使い方がありますか?もちろんあります。それはprovide/injectを使ってコンポーネントを作ることです。
    provide/injectを使ってコンポーネントを作成します。
    provide/injectを使ってコンポーネント開発を行うのは、Vue公式文書で提唱されているやり方です。
    私がよく知っているelement UIを例に挙げます。
    element UIにはButton(ボタン)コンポーネントがあり、Form(フォーム)コンポーネントで使用すると、そのサイズは外層のFormItemコンポーネントとより外層のFormコンポーネントのsize属性に影響されます。
    通常のプログラムであれば、プロpsを通じてFormから始まり、属性値を次から次へと送ることができます。二重に渡すだけでいいようです。受け入れられます。しかし、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を理解して、あなたはいくつかの普通ではない景色を発見することができるかも知れなくて、あなたにいくつか問題を解決する時、功の半ばです。
    以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。