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

推薦する

Vueは小さな天気予報アプリケーションを実装します

これは私が Vue フレームワークを独学していたときに真似したウェブサイトです。いくつかの都市の天気...

Mybatis mysqlの削除操作では、最初のデータメソッドのみを削除できます。

バグ図のように、削除文とパラメータをデータベースにコピーして実行し、2つのデータを削除しようとしたの...

更新SQL文に基づくMySQLロックの理解

序文MySQL データベース ロックは、データの一貫性を実現し、同時実行性の問題を解決するための重要...

HTML テーブルタグチュートリアル (7): 背景色属性 BGCOLOR

テーブルの背景色は、BGCOLOR 属性を通じて設定できます。基本的な構文<テーブル BGCO...

Vueプロジェクトのパッケージ化の詳細な説明

目次1. 関連構成ケース1(使用ツールはvue-cil)ケース2(使用するツールはwebpack) ...

Vue3.0のさまざまなリスニング方法の包括的な概要

目次リスナー1.ウォッチエフェクト2.見る1.1 聴くための最初の方法1.2 聞く2つ目の方法1.3...

jsの継承の6つの方法を詳しく解説

プロトタイプチェーン継承プロトタイプ継承は、ECMAScript における主な継承方法です。基本的な...

div を下から上にスライドさせる CSS3 の例

1. まず、CSS3 のターゲット セレクターを使用し、a タグを使用して id セレクターを指定し...

データベースアカウントのパスワード暗号化の詳細な説明と例

データベースアカウントのパスワード暗号化の詳細な説明と例データベースアカウントとパスワードはデータベ...

nginx の 2 つのモジュールの proxy_pass の違い

1. 1.ngx_stream_proxy_moduleモジュールのproxy_passディレクティ...

Linux での MySql centos7 のバイナリコンパイルとインストールに関するチュートリアル

// これをインストールするのに丸一日かかったので、記録するためにメモを書きました。 //何か問題が...

Node.jsはMySQLデータベースの実戦記録を追加、削除、変更、チェックします

目次プロジェクトでデータベースを操作する3つのステップデータベースを操作するための具体的な手順1: ...

複数のサーバーにNginxリバースプロキシを実装する方法

Nginx は複数のサーバーをリバース プロキシします。つまり、nginx に異なるリクエストを送信...

MySQL の自動インクリメント主キーが連続していないのはなぜですか?

目次1. はじめに2. 自己増分ストレージの説明3つの自己付加価値修正メカニズム4. 自己評価を修正...

ページスピードの最適化の概要

インターネットは人々の生活にますます欠かせないものになってきていると思います。 Ajax や fle...