React のグローバル状態管理の 3 つの基本メカニズムの調査

React のグローバル状態管理の 3 つの基本メカニズムの調査

序文

最新のフロントエンド フレームワークはすべて、コンポーネントベースの方法でページを開発します。論理的な関係に従ってページをさまざまなコンポーネントに分割し、さまざまなコンポーネントを個別に開発してから、レイヤーごとに組み立てます。ルートコンポーネントを ReactDOM.render または Vue の $mount メソッドに渡すと、コンポーネントツリー全体がトラバースされ、対応する DOM にレンダリングされます。

コンポーネントはカスタマイズのためにいくつかのパラメータを渡すことをサポートしており、いくつかのインタラクティブな状態を内部的に保存することもできます。また、パラメータと状態が変更された後に、DOM の対応する部分を自動的に再レン​​ダリングします。

これらは論理的には異なるコンポーネントに分割されていますが、すべて同じアプリケーションの異なる部分であり、必然的に相互に通信して連携する必要があります。複数のレイヤーのコンポーネントがパラメータを介して通信する場合、中間レイヤーのコンポーネントはこれらのパラメータを透過的に渡す必要があります。パラメータは本来、コンポーネントをカスタマイズするために使用するものであり、通信のために意味のないパラメータを追加すべきではありません。

したがって、コンポーネント通信では、通常、コンポーネント パラメータをレイヤーごとに送信するのではなく、両方の当事者がアクセスできるグローバルな場所にコンポーネント パラメータを配置します。

グローバル状態管理には多くの具体的なソリューションがあるかもしれませんが、その基礎となるメカニズムは、props、context、state の 3 つにすぎません。

次に、これら 3 つのメソッドがグローバル状態をどのように保存および転送するかを調べてみましょう。

小道具

グローバル オブジェクトを介して通信することができ、1 つのコンポーネントがデータを保存し、他のコンポーネントがそのデータを取得します。

ストアからデータを取得するためにコンポーネントにコードを記述するのは、かなり煩わしい作業です。ストアを使用するすべてのコンポーネントにこのコードを追加することはできません。このロジックを高階コンポーネントに抽出し、それを使用してコンポーネントとストアを接続することができます。データはパラメータを通じてコン​​ポーネントに注入されるため、ソースはコンポーネントに対して透過的になります。

react-redux の機能は次のとおりです:

'react-redux' から connect をインポートします。

関数 mapStateToProps(状態) {
    戻り値: state.todos }
}
  
関数 mapDispatchToProps(ディスパッチ) {
    bindActionCreators({ addTodo }, dispatch) を返します。
}
  
デフォルトの connect(mapStateToProps, mapDispatchToProps)(TodoApp) をエクスポートします。

さらに、redux は、コンポーネントからストアに送信されたアクションをインターセプトして一連の非同期ロジックを実行できるミドルウェア メカニズムも提供します。

より一般的なミドルウェアには、redux-thunk、redux-saga、redux-obervable などがあり、非同期プロセスを記述および整理し、非同期ロジックをカプセル化して再利用するためのさまざまな方法をサポートしています。

mobox、reconcil などの同様のグローバル状態管理ライブラリも、props を通じてコン​​ポーネントにグローバル状態を挿入します。

コンテクスト

クロスレイヤーコンポーネント通信にはサードパーティのソリューションが必要ですか? いいえ、React 自体もこの種の通信のためのコンテキストメカニズムを提供します。

React.createContext の API は、それぞれ状態の提供と状態の取得に使用される Provider と Consumer を返します。また、props を通じてターゲット コンポーネントに透過的に渡されます。 (ここでの Consumer は、同じ効果を持つ useContext API に置き換えることもできます。クラス コンポーネントは Provider を使用し、関数コンポーネントは useContext を使用します)

基本的には redux ソリューションと違いはないように見えますが、主な違いは、コンテキストには非同期ロジックを実行するミドルウェアがないことです。

したがって、コンテキスト ソリューションは非同期ロジックのないグローバル データ通信に適していますが、Redux は複雑な非同期ロジックを編成するのに適しています。

ケースコードは次のとおりです。

const テーマ = {
  ライト:
    前景: "#000000",
    背景: "#eeeeee"
  },
  暗い:
    前景: "#ffffff",
    背景: "#222222"
  }
};

ThemeContext を React.createContext(themes.light);

関数App() {
  戻る (
    <ThemeContext.Provider 値 = {themes.dark}>
      <ツールバー />
    </テーマコンテキスト.プロバイダー>
  );
}

関数ツールバー(props) {
  戻る (
    <div>
      <テーマボタン />
    </div>
  );
}

関数ThemedButton() {
  テーマコンテキストを使用します。
  戻る (
    <button style={{ background: theme.background, color: theme.foreground }}>
      テーマのコンテキストによってスタイルが決まります!
    </ボタン>
  );
}

これについて考えたことがあるでしょうか。プロパティと状態が変化するとコンポーネントを再レンダリングするのが普通ですが、コンテキストの変化によってレンダリングがどのようにトリガーされるのでしょうか。

実際、React は内部でいくつかの処理を行っています。コンテキスト値が変更されると、すべての子コンポーネントを走査し、コンテキスト値を使用するコンポーネントを見つけて、その更新をトリガーします。

したがって、props、state、context はすべて再レンダリングをトリガーできます。


Redux とコンテキストのソリューションは、1 つはサードパーティ製で、もう 1 つは組み込みです。どちらもプロパティを介して値を渡したり、フックを介して値を取得したりしますが、どちらもコンポーネントの外部にあり、状態はコンポーネントの内部にあります。状態を介してグローバル状態を共有するにはどうすればよいでしょうか。

実際、クラス コンポーネントの状態ではこれを行うことはできませんが、関数コンポーネントの状態ではこれを行うことができます。これは、useState のフック API を通じて作成され、useState をカスタム フックに抽出して、さまざまな関数コンポーネントに導入して使用できるためです。

React をインポートし、{useState} を 'react' から取得します。

const useGlobalState = (初期値) => {
    定数[globalState、setGlobalState] = useState(initialValue);
    [globalState、setGlobalState]を返します。
}

関数ComponentA() {
    定数[globalState、setGlobalState] = useGlobalState({name: 'aaa'});
    
    グローバル状態を設定します({名前: bbb});
    <div>{globalState}</div> を返します
}

関数ComponentA() {
    定数[globalState、setGlobalState] = useGlobalState({name: 'aaa'});
 
    <div>{globalState}</div> を返します
}

上記のコードはグローバル状態を共有できますか?

これは実際には不可能です。なぜなら、各コンポーネントが独自の fiber.memorizedState に新しいオブジェクトを配置し、変更によって独自のオブジェクトも変更されるからです。

この2つのuseStateの初期値を同じオブジェクトに向ければ良いのではないでしょうか?

このようにして、複数のコンポーネントが同じデータに対して操作を行うことができます。

上記のコードは次のように変更する必要があります。

グローバルVal = {
    名前: ''
}

定数useGlobalState = () => {
    定数[globalState、setGlobalState] = useState(globalVal);

    関数 updateGlobalState(val) {
        グローバルVal = val;
        グローバル状態を設定します(val);
    }

    [globalState、updateGlobalState]を返します。
}

このように、各コンポーネントによって作成された状態は同じオブジェクトを指し、グローバル状態も共有できます。

ただし、ここでは前提があります。つまり、オブジェクトのプロパティのみを変更でき、オブジェクト自体を変更することはできません。

要約する

現在のフロントエンドページの開発方法は、ページをロジックに応じてコンポーネントに分割し、各コンポーネントを個別に開発し、レイヤーごとに組み立てて、ReactDOM.render または Vue の $mount に渡してレンダリングするというものです。

コンポーネントは、props と state を使用してカスタマイズし、インタラクション状態を保存できます。変更された場合は自動的に再レン​​ダリングされます。さらに、コンテキストが変更されると、contxt データを使用する子コンポーネントが検出され、再レンダリングがトリガーされます。

コンポーネントは互いに連携するため、通信は避けられません。Props はコンポーネントをカスタマイズするために使用されるものであり、意味のない props を渡すために使用すべきではないため、グローバル オブジェクトを介して転送する必要があります。

React 自体はコンテキスト ソリューションを提供します。CreateContext は、それぞれデータの保存と読み取りに使用される Provider と Consumer を返します。関数コンポーネントでは、Provider の代わりに useContext を使用することもできます。

コンテキストはグローバル状態を共有できますが、非同期ロジックの実行メカニズムはありません。複雑な非同期ロジックがある場合は、非同期プロセスを整理し、非同期ロジックをカプセル化して再利用するためのミドルウェアメカニズムを提供する redux を使用する必要があります。たとえば、redux-saga では、非同期ロジックを saga にカプセル化して再利用できます。
context と redux はどちらも、コンポーネントに対して透過的で非侵入的な、props を介したコンポーネントへのデータ注入をサポートしています。

実際、useState でカプセル化されたカスタム フックは、初期値を同じオブジェクトにポイントすることでグローバル データ共有の目的を達成することもできますが、制限があります。オブジェクトのプロパティのみを変更でき、オブジェクト自体を変更することはできません。実際にはこれよりもコンテキストを使用する方が良いのですが、これを行うことができるということだけ述べておきます。

簡単にまとめると、context と redux はどちらもグローバル状態管理に使用できます。1 つは組み込みで、もう 1 つはサードパーティ製です。非同期ロジックがない場合は context を使用し、非同期ロジックがある場合は redux を使用します。

これで、React のグローバル状態管理の 3 つの基本的なメカニズムに関するこの記事は終了です。React のグローバル状態管理に関するより関連性の高いコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Reactの状態管理の3つのルールのまとめ
  • ReactでVueの状態管理メソッドを使用する例
  • さまざまなReact状態マネージャーの解釈と使用方法

<<:  Linux 上でプライベート Git サーバーを構築するための詳細なチュートリアル

>>:  MySQL INT型の完全な分析

推薦する

純粋なCSSを使用してスイッチ効果を実現する

まずアイデアはこの効果を実現するには、 <input type="checkbox&...

HTML チュートリアル、optgroup 要素の理解

カテゴリ選択を選択します。テストの結果、IE と FF はこの要素を適切にサポートできることがわかり...

Quickjs は JavaScript サンドボックスの詳細をカプセル化します

目次1. シナリオ2. 基盤となるAPIを簡素化する2.1 自動的に破棄を呼び出す2.2 VM値を作...

SSHのssh-keygenコマンドの基本的な使い方の詳細な説明

SSH 公開鍵認証は、SSH 認証方式の 1 つです。 SSH パスワードフリーのログインは公開鍵認...

JavaScriptで配列かどうかを判断するためのさまざまな方法のまとめ

目次序文配列.isArrayコンストラクタインスタンスプロトタイプオブジェクト.プロトタイプ.toS...

JavaScript モバイル H5 画像生成ソリューションの説明

現在、WeChatパブリックアカウントの運用活動が多く、写真を生成する必要があります。生成された写真...

2012年のベストWebデザイン作品レビュー[パート1]

新年の初めに、友人の健康と2013年が素晴らしい年となることを心からお祈りいたします。この記事では、...

Linux で ffmpeg をインストールするための詳細なチュートリアル

1. CentOS Linuxにffmpegをインストールする1.ダウンロードして解凍する http...

Linux の Makefile とは何ですか? どのように機能しますか?

この便利なツールでプログラムをより効率的に実行およびコンパイルしますMakefile は自動コンパイ...

Vue画像拡大鏡コンポーネントのカプセル化と使用方法の詳細な説明

Vue画像拡大鏡コンポーネントパッケージに基づいて、参考までに具体的な内容は次のとおりです。画像拡大...

トークン生成と検証を実装するミニプログラム

目次プロセスデモミニプログラムバックエンドインターフェースプロセス各リクエストインターフェースは検証...

フロントエンドのパフォーマンス最適化を学習するための準備として、HTML ページのレンダリング プロセスを理解する (続き)

昨夜、ブラウザのレンダリングプロセスに関するエッセイを書きましたが、小さなコードで説明しただけでした...

ブログデザイン ウェブデザイン デビュー

私がデザインした最初の Web ページは次のとおりです。 私はこの業界に7年間在籍し、プログラミング...

DockerはRedis5.0をビルドし、データをマウントします

目次1. 永続データの簡単なマウント2. DockerFileでイメージをビルドし、設定ファイルを指...

JavaScript を使用して div の位置をドラッグして入れ替える例

1 実施原則これは、DOM 要素の dragstart/ondragover/ondrop イベント...