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型の完全な分析

推薦する

ログインスライダー検証を実装するJavaScript

この記事では、ログインスライダー検証を実装するためのJavaScriptの具体的なコードを参考までに...

Vue を使用して Web ページのスクリーンショットを撮る方法をご存知ですか?

目次1. html2Canvasをインストールする2. 必要なVueコンポーネントを導入する3. ス...

React NativeのScrollViewプルダウンリフレッシュ効果

この記事では、React Native ScrollViewのプルダウンリフレッシュ効果の具体的なコ...

Linux 構成で MySQL データベースへのリモート接続が失敗する問題の解決方法

今日は、Linux でリモート アクセス用に MySQL データベースを構成する方法について質問があ...

MySQLの保存時間の不一致の問題を解決する

Java を使用してシステム時間を取得し、それを MySQL データベースに保存した後、時間タイプが...

MySQL サーバーにおける SSD パフォーマンスの問題の詳細な分析とテスト

【質問】 HP サーバーを使用しています。SSD が IOPS 約 5000 を書き込むと、%uti...

CSS の 4 つのインポート方法と優先順位の簡単な分析

第一に: CSSを導入する4つの方法CSS を導入する方法には、インライン スタイル、埋め込みスタイ...

MySQL では SQL ステートメントはどのように実行されますか?

目次1. MySQLアーキテクチャの分析1.1 コネクタ1.2 クエリキャッシュ1.3 アナライザー...

Mysql5.7.14 インストールと設定方法操作グラフィックチュートリアル(パスワード問題解決)

この記事は主に、以前のインストール方法を使用して MySQL 5.7.14 をインストールするときに...

Vueの監視プロパティの詳細

目次1.watchは一般的なデータ(数値、文字列、ブール値)の変更を監視します。 1. 数値2. 文...

InnoDB エンジンのパフォーマンスを最適化するための my.cnf パラメータ構成

私はインターネット上で数え切れないほどの my.cnf 構成を読みましたが、言及されている構成のほと...

スクロールバーを非表示にしながらもスクロール効果を維持する純粋な CSS (モバイルと PC)

携帯モバイル ページは Chrome および Safari とのみ互換性があればよいため、カスタム ...

Vue.js での VNode の使用

VNodeとはvue.js には VNode クラスがあり、これを使用してさまざまな種類の vnod...

MySQL データベース開発の 36 の原則 (要約)

序文これらの原則は実際の戦闘から要約されています。あらゆる原則の背後には血なまぐさい教訓があるこれら...

MySQL 8.0.21 のインストール手順と問題解決

公式サイトをダウンロードまず公式ウェブサイトにアクセスしてMySQLをダウンロードしてくださいリンク...