コンテキスト


Reactにおいて、親コンポーネントから子コンポーネントにデータを渡す場合、propsオブジェクトを使用してデータを渡す.
ただし、データが必要なサブコンポーネントの数が多い場合は、同じコードを繰り返し入力する必要があります.重複構造がある場合、中間コンポーネントは、データを必要とせずにサブコンポーネントにデータを渡す義務があります.
この場合,コンテキスト(Context)を用いることで処理効率を向上させることができる.

コンテキストが必要です。


必要なコンテキストから簡単な例を次に示します.
Appコンポーネントでは、propsオブジェクトを使用してユーザ情報がサブコンポーネントに伝達され、UserViewerコンポーネントでこのデータを使用してレンダリングされる簡単な例である.UserWrap要素はユーザ情報を必要としないので、propsをサブ要素に戻すことが分かる.
データを使用する構成部品が下にある場合、中間の構成部品は意味なくデータのみを伝達し、構成部品ツリーが複雑であるほど問題が大きくなります.
では、コンテキスト修正コードを使用する前に、APIからどのように使用するかを確認します.

コンテキストAPI


React.createContext(defaultValue)
ex) const ColorContext = React.createContext('red')コンテキストオブジェクトを作成する方法.
生成されたコンテキストオブジェクトは、データの変更および検出に使用できるProviderコンポーネントおよびConsumerコンポーネントを有する.
パラメータとして渡されるdefaultValueの場合、サブスクリプションコンテキストのコンポーネントに適切なProviderが見つからない場合、デフォルトではこの値が使用されます.
Context.Provider
ex)
<ColorContext.Provider value="blue" >
  ...ManyComponent
</ColorContext.Provider>
<Context.Priveder>コンポーネントは、コンテキストを購読しているサブコンポーネントのコンテキストの変化を通知するコンポーネントである.value propを使用して渡されたデータは、コンテキストを購読するすべてのコンポーネントに対してグローバルデータである.
したがって、伝達可能な要素の数に制限されずに伝達することができる.
Class.contextType
ex)
class AnyClass extends React.Component {
  render() {
  	return <h1>Color is {this.context}</h1>
  }
}
AnyClass.contextType = ColorContext;
クラス構成部品のProviderパーセントを使用して、構成部品をコンテキストに購読できます.
一致するコンテキストのうち最も近いcontextTypeProviderを優先的に転送し、value propを使用して要素内部にデータをインポートする.
欠点は、クラスコンポーネントにのみアクセスでき、this.contextはパーセントを使用して1つのコンテキストしか購読できないことです.
Context.Consumer
ex)
class AnyClass extends React.Component {
  render() {
    return (
      <ColorContext.Consumer>
        {color => <h1>Color is {color}</h1>}
      </ColorContext.Consumer>
    );
  }
}
上記のcontextTypeと同様に、これはコンテキストを購読する方法の1つです.
違いは、Class.contextTypeコンポーネントが関数コンポーネントでコンテキストを購読し、1つのコンポーネントで複数のコンテキストを購読することを可能にすることである.
次に、Context.Consumer要素のサブアイテムは関数形式でなければならないことに注意してください.

整理する


上記のContext.ConsumerおよびClass.contextTypeを使用してコンテキストを購読する構成部品は、Context.Consumerと呼ばれ、consumerにあるすべての子Providerは、親構成部品が再レンダリングされるかどうかにかかわらず、consumerProviderで変更されると、value prop度が再レンダリングされます.
これにより、コンテキストを必要としない構成部品が更新されず、パフォーマンスの最適化が実現されます.
また、コンテキストを使用するとコンポーネントの再利用性が低下するため、コンテキストを使用するたびに、コンポーネントを合成することでこの問題を解決できるかどうかをまず考慮します.
ここでは基本的なコンテキストAPIの使用方法です.では、コンテキストを直接使用しましょう.

既存のコードの変更


上で使用したコードをコンテキストを使用するコードとして再記述します.

使用コンテキストとは異なり、consumerコンポーネントはデータを一切伝達せず、UserWrapコンポーネントおよびUserViewerコンポーネントを使用してProviderコンポーネントからConsumerコンポーネントに直接データを伝達することが分かる.
次に、ネストされたコンテキストとstateドラッグ&ドロップを使用して、より複雑な例を作成します.
UserContext.js

コンテキストオブジェクトを外部のモジュールにエクスポートします.
index.js
Appのファイルになります.UserViewerに変更されたentry point関数は、state要素のchangeUserName()に変換され、setUserContext.Providerからvalue propに変換されたstate.nameが重畳され、value propにデータが伝達される.UserContext.Provider要素のすべてのサブ要素は、consumerを介してUserWrapconsumerにアクセスできるようになった.
User.js
App要素において、stateUserFormsetUserContextsetter方法であり、AppchangeUserName()UserContextname方法である.
整理後、Appstate.nameユニットが変更されると、イベントハンドラUserFormが呼び出され、親コンポーネントinputsetterが変更される.
これにより、Appstateが変化し、UserContext.Providerの構成部品が再レンダリングされ、value propによって渡されたconsumerの値を使用して再レンダリングされます.
では、正常に動作しているかどうか見てみましょう.

意図通りに行動するのが見えます.

コンテキストの使用上の注意点

UserContext.Consumer素子のnameと従来のContext.Providerとの差異を参照に比較した.
したがって、下図に示すように、value propで新しいオブジェクトを作成して渡すと、以前のオブジェクトと区別がないと思っていても、参照値が異なるためにvalueが変化し、サブアセンブリに不要なレンダリングが生じたと考えられます.
class MyComponent extends React.Component {
    render() {
        return (
            <Context.Provider value={{ name : 'default' }}>
                ...ManyComponent
            </Context.Provider>
        );
    }
}
これを回避するために、オブジェクトをvalue propに渡す場合は、次のvalueを使用してオブジェクトの参照値を渡します.
class MyComponent extends React.Component {
    consturctor(props) {
        super(props);
        this.state = {
            user : { name : 'default' }
        };
    }

    render() {
        return (
            <Context.Provider value={this.state.user}>
                ...ManyComponent
            </Context.Provider>
        );
    }
}
参考資料
Context - Reacthttps://ko.reactjs.org/docs/context.html