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

推薦する

Mysql が CPU を過剰に占有する場合の最適化方法 (必読)

Mysql が CPU を占有しすぎる場合、どこから最適化を開始すればよいでしょうか? CPU 使...

MySQL 8.0 の新しいリレーショナル データベース機能の詳細な説明

序文MySQL 8.0 の最新バージョンは 8.0.4 rc であり、正式版は近日中にリリースされる...

フロントエンドJavaScriptの動作原理

目次1. JavaScript エンジンとは何ですか? 2. V8エンジン3. ランタイム環境4. ...

MySQL 中断された接続警告ログの分析

序文:場合によっては、MySQL に接続されたセッションが異常終了することが多く、エラー ログに「通...

Vue ログインページでクッキーを使用してパスワードを 7 日間記憶する方法

問題の説明プロジェクトのログインページでは、7日間パスワードを記憶する必要がある機能があります。この...

ウェブデザインのためのロイヤルブルーのカラーマッチング入門

古典的な色の組み合わせは力と権威を伝え、強いロイヤルブルーはあらゆる古典的な色の組み合わせの中心的な...

VMware Workstation Pro 16 グラフィックチュートリアル (CentOS8 仮想マシン クラスタの構築)

目次準備VMware Workstation Pro 16 をインストールするLinux仮想マシンの...

Vueでaxiosをカプセル化する方法

目次1. インストール1. はじめに3. インターフェースルートアドレス4. 使用例4.1 ダウンロ...

HTML Selectは、デフォルトの選択を設定するためにselected属性を使用します。

オプションに属性 selected = "selected" を追加すると、それ...

HTML ドラッグ アンド ドロップ機能の実装コード

Vueベースこの機能の核となるアイデアは、JavaScript コードを通じてページ上のノードの左余...

ROS で Turtlebot3 移動ロボットを制御するための基本的なチュートリアル

中国語チュートリアルhttps://www.ncnynl.com/category/turtlebo...

uniapp アプレットでウォーターフォール フロー レイアウトを実装するためのアイデアとコード

1. はじめに今、ウォーターフォールフローについて書くことは、古い内容の焼き直しと見なされますか?気...

Nginx プロキシを使用してインターネットを閲覧する方法

私は通常、Tomcatや他のアプリケーションのリバースプロキシとしてnginxを使用しています。実際...

MySQL Routerのインストールと展開

目次01 MySQLルーターの紹介MySQL Router とは何ですか? 02 MySQLルータの...