react+reduxを使用してカウンター機能を実装すると発生する問題

react+reduxを使用してカウンター機能を実装すると発生する問題

Redux はシンプルな状態マネージャーです。その歴史をたどることはしません。使用法の観点から見ると、すべてのアプリケーション データを格納する状態オブジェクトを含むグローバル オブジェクト ストアが提供され、ストアにはいくつかのリデューサー メソッドが用意されています。これらのメソッドをカスタマイズして、呼び出し元が状態の値を変更できるようにすることができます。状態の値は読み取り専用であり、変更する必要がある場合にのみリデューサーを通じて変更する必要があります。

再登場

  • コアオブジェクト: ストア
  • データストレージ: 状態
  • ステータス更新送信インターフェース: ==dispatch==
  • ステータス更新送信パラメータ: ==アクション== タイプとペイロード付き
  • 状態更新計算: ==reducer==
  • 制限: リデューサーは純粋な関数である必要があり、非同期をサポートしていません
  • 機能: ミドルウェアのサポート

リアクト + Redux

recat で redux を使用しない場合に発生する問題

Reactでは、コンポーネントの通信は一方通行です。最上位コンポーネントはprops属性を通じて下位コンポーネントにデータを渡すことができますが、下位コンポーネントは上位コンポーネントにデータを渡すことができません。下位コンポーネントのデータを変更するには、上位コンポーネントが下位コンポーネントにデータを変更するメソッドを渡す必要があります。プロジェクトが大きくなるほど、コンポーネント間でデータを渡すことがますます難しくなります。

ReactにReduxを追加するメリット

データの管理には redux を使用します。Store はコンポーネントから独立しているため、データ管理もコンポーネントから独立しており、コンポーネント間でデータを転送するのが難しいという問題が解決されます。

reduxの使用

reduxをダウンロード

npm インストール redux react-redux

Reduxワークフロー

  1. コンポーネントはディスパッチを通じてアクションをトリガーします
  2. ストアはアクションを受け入れ、それをリデューサーにディスパッチします。
  3. リデューサーはアクションの種類に応じて状態を変更し、変更されたデータをストアに返します。
  4. コンポーネントはストア内の状態をサブスクライブし、ストア内の状態の更新はコンポーネントに同期されます。

react+reduxを使用してカウンターを実装する

1. プロジェクトを作成し、reduxをインストールする

# React スキャフォールディングがインストールされていない場合は、このコマンドを実行して React スキャフォールディングをインストールします。npm install -g create-react-app
# react プロジェクトを作成する create-react-app プロジェクト名 # プロジェクトを入力する cd プロジェクト名 # redux をインストールする
npm インストール redux reate-redux

2. reduxを導入し、最初に実装したコードに従ってreactでカウンターを実装します。

//index.js
'react' から React をインポートします。
'react-dom' から ReactDOM をインポートします。
'./App' から App をインポートします。
'redux' から createStore をインポートします。

定数初期状態 = {
  カウント: 0
}
関数リデューサー(状態 = 初期状態、アクション) {
  スイッチ(アクションタイプ){
    ケース '増分':
      戻る {
        カウント: 状態.count + 1
      }
    ケース '減少':
      戻る {
        カウント: 状態.count - 1
      }

    デフォルト:
      状態を返す
  }
}
const ストア = createStore(リデューサー)

定数増分 = {
  タイプ: '増分'
}

定数減分 = {
  タイプ: '減少'
}

関数Count() {
  <div> を返す
    <button onClick={() => store.dispatch(increment)}>+</button>
    {store.getState().count}
    <button onClick={() => store.dispatch(decrement)}>-</button>
  </div>
}

ストア.subscribe( () => {
  コンソールログ(ストア.getState())
  ReactDOM.render() は、
    <React.StrictMode>
      <カウント />
    </React.StrictMode>,
    ドキュメント.getElementById('ルート')
  );
})

ReactDOM.render() は、
  <React.StrictMode>
    <カウント />
  </React.StrictMode>,
  ドキュメント.getElementById('ルート')
);

明らかに、上記の方法はカウンターの機能を実現できますが、コンポーネントは通常別々のファイルにあり、この方法では他のコンポーネントの Store を取得できないため、実際のプロジェクトでは使用できません。

カウンターケースコードの最適化 - ストアをグローバルにアクセス可能にする

ストア取得問題を解決するには、react-reduxを使用する必要があります。react-reduxは、プロバイダーコンポーネントと接続メソッドを提供します。

コンポーネントの提供

作成したストアをグローバルな場所に配置して、コンポーネントがストアを取得できるようにするコンポーネントです。プロバイダ コンポーネントを介して、ストアはグローバル コンポーネントがアクセスできる場所に配置されます。プロバイダは、ストアを最も外側のコンポーネントに配置することを要求します。

接続する

connectはストア内の状態を購読するのに役立ち、状態が変化したときにコンポーネントを再レンダリングするのに役立ちます。

connectメソッドを通じてストア内の状態を取得し、ストア内の状態をpropsにマッピングすることができます。

ディスパッチメソッドはconnectメソッドを通じて取得できる。

connect のパラメータは、ストア内の状態を取得できる関数です。この関数はオブジェクトを返す必要があります。このオブジェクトに書き込まれた内容は、コンポーネントの props プロパティにマッピングされます。

connect 呼び出しの後、関数が返されます。どのコンポーネントのプロパティをマップする必要があるかを connect に伝えるために、この関数を渡す必要があります。

新しいコンポーネントフォルダを作成し、Count.jsファイルを作成します。

'react' から React をインポートします

関数Count() {
    <div> を返す
        <button onClick={() => store.dispatch(increment)}>+</button>
        {store.getState().count}
        <button onClick={() => store.dispatch(decrement)}>-</button>
    </div>
}

エクスポートのデフォルト数

プロバイダコンポーネントを導入し、最外層に配置し、ストアを定義します。

ReactDOM.render() は、
  // プロバイダ コンポーネントを使用して、グローバル コンポーネントがアクセスできる場所にストアを配置します。プロバイダでは、ストアを最も外側のコンポーネントに配置する必要があります <Provider store={store}><Count />></Provider>,
  ドキュメント.getElementById('ルート')
);

connectの使用に応じてコンポーネントをラップするconnectメソッドを導入する

const mapStateProps = 状態 => ({
    カウント: 状態.カウント、
    '1' です
})
// connect のパラメータは関数です。この関数はストア内のステータスを取得できます。この関数はオブジェクトを返す必要があります。このオブジェクトに書き込まれたコンテンツは、コンポーネントの props プロパティにマップされます。// connect 呼び出しの後、関数が返されます。返された関数は、どのコンポーネントの props にマップする必要があるかを connect に伝えるために渡す必要があります。
エクスポートデフォルトconnect(mapStateProps)(Count)

Countコンポーネントを変更し、アクションをこのファイルにコピーします

定数増分 = {
    タイプ: '増分'
}

定数減分 = {
    タイプ: '減少'
}
関数Count({count, dispatch}) {
    <div> を返す
        <button onClick={() => {dispatch(increment)}}>+</button>
        <span>{count} 個</span>
        <button onClick={() => {dispatch(decrement)}}>-</button>
    </div>
}

これでプロジェクトを実行できるようになりましたが、Count コンポーネントの送信アクションのコードが長いため、ビューの読みやすさに影響するため、コードを最適化する必要があります。

カウンターケースコードの最適化 - ビュー内のコードを読みやすくする

ビュー コードが読みやすくなるように、ビュー内で関数を直接呼び出すことを目指します。そのためには、connect の 2 番目のパラメータを使用する必要があります。このパラメータは、ディスパッチ メソッドです。この関数は、オブジェクトを返すために必要です。返されたオブジェクトの内容は、コンポーネントの props プロパティにマップされます。

connectの2番目のパラメータとして変数を宣言し、この変数でさまざまなアクション操作を実行するオブジェクトを返します。

// connect の 2 番目のパラメータは関数です。この関数のパラメータはディスパッチ メソッドです。オブジェクトを返す必要があります。このオブジェクトのプロパティはコンポーネントのプロパティにマップされます。const mapDispatchToProps = dispatch => ({
    増分(){
        急送({
            タイプ: '増分'
        })
    },
    減算(){
        急送({
            タイプ: '減少'
        })
    }
})

// connect のパラメータは関数です。この関数はストア内のステータスを取得できます。この関数はオブジェクトを返す必要があります。このオブジェクトに書き込まれたコンテンツは、コンポーネントの props プロパティにマップされます。// connect 呼び出しの後、関数が返されます。返された関数は、どのコンポーネントの props にマップする必要があるかを connect に伝えるために渡す必要があります。
エクスポートデフォルト connect(mapStateProps, mapDispatchToProps)(Count)

コンポーネント内のプロパティを構成し、ビュー内でイベントを直接バインドする

関数 Count({count,increment,decrement}) {
    <div> を返す
        <button onClick={increment}>+</button>
        <span>{count} 個</span>
        <button onClick={decrement}>-</button>
    </div>
}

この最適化により、アクションをトリガーするためにディスパッチを呼び出すコードが繰り返されていることがわかったので、引き続き最適化する必要があります。

アクションをトリガーするためにディスパッチを呼び出すメソッド内のコードの重複を最適化する

bindActionCreatorsを使用してディスパッチトリガーアクション操作を簡素化し、bindActionCreatorsを使用してアクションを実行する関数を生成します。

bindActionCreatorsには2つのパラメータがあり、最初のパラメータはアクションを実行するオブジェクト、2番目のパラメータはディスパッチメソッドです。

アクション操作を分離し、新しいstore/actions/counter.actions.jsファイルを作成し、このファイルにアクション操作を別々に入れてエクスポートします。

エクスポート const increment = () => ({type: 'increment'})
エクスポート const decrement = () => ({type: 'decrement'})

Count.jsにカウンターアクションをインポートし、bindActionCreatorsメソッドを使用してディスパッチ実行アクション関数を生成します。

'redux' から {bindActionCreators} をインポートします。
'./../store/actions/counter.actions' から counterActions として * をインポートします。


const mapDispatchToProps = ディスパッチ => (bindActionCreators(counterActions, ディスパッチ))
// connect のパラメータは関数です。この関数はストア内のステータスを取得できます。この関数はオブジェクトを返す必要があります。このオブジェクトに書き込まれたコンテンツは、コンポーネントの props プロパティにマップされます。// connect 呼び出しの後、関数が返されます。返された関数は、どのコンポーネントの props にマップする必要があるかを connect に伝えるために渡す必要があります。
エクスポートデフォルト connect(mapStateProps, mapDispatchToProps)(Count)

コード最適化のこの時点で、redux コードがコンポーネントと統合されていることがわかりました。そのため、独立したものに分割する必要があります。なぜ redux を抽出する必要があるのでしょうか?コード構造をより合理的なものにしたいからです

カウンターをリファクタリングし、redux関連のコードを抽出する

リデューサー関数を別のファイルに抽出し、ストアの作成を別のファイルに抽出します。

リデューサーとアクションの両方で文字列を記述しましたが、文字列のプロンプトがないため、単語の間違いなどの低レベルの間違いを防ぐために文字列を定数として定義します。新しいsrc/store/const/counter.const.jsファイルを作成します。

エクスポート const INCREMENT = 'increment'
エクスポート const DECREMENT = 'decrement'

新しいsrc/store/reducers/counter.reducers.jsファイルを作成し、このファイルにreducer関数を抽出します。

'./../const/counter.const' から {INCREMENT、DECREMENT} をインポートします。
定数初期状態 = {
    カウント: 0
}
// eslint は次の行のインポートを無効にする / 匿名のデフォルトエクスポートを無効にする
エクスポート デフォルト (状態 = initialState、アクション) => {
    スイッチ(アクションタイプ){
        ケース増分:
            戻る {
                カウント: 状態.count + 1
            }
        ケースデクリメント:
            戻る {
                カウント: 状態.count - 1
            }

        デフォルト:
            状態を返す
    }
}

アクション内の文字列をインポートされた変数に変更する

'./../const/counter.const' から {INCREMENT、DECREMENT} をインポートします。

エクスポート const increment = () => ({type: INCREMENT})
エクスポート const デクリメント = () => ({type: DECREMENT})

src/store/index.jsファイルを作成し、このファイルにストアを作成してエクスポートします。

'redux' から createStore をインポートします。
'./reducers/counter.reducers' からリデューサーをインポートします。

エクスポート const store = createStore(reducer)

ストアをインポートするファイルで、プロジェクト内のストアファイルにストアをインポートするように変更します。

'react' から React をインポートします。
'react-dom' から ReactDOM をインポートします。
'./components/Count' から Count をインポートします。
'./store' から { store } をインポートします
'react-redux' から { Provider } をインポートします。
/**
 * react-reduxは、reactとreduxの完璧な組み合わせです。 * プロバイダーは、作成されたストアをグローバルな場所に配置して、コンポーネントがストアを取得できるようにするコンポーネントです。
* connect はメソッドです */


ReactDOM.render() は、
  // プロバイダ コンポーネントを使用して、グローバル コンポーネントがアクセスできる場所にストアを配置します。プロバイダでは、ストアを最も外側のコンポーネントに配置する必要があります <Provider store={store}><Count />></Provider>,
  ドキュメント.getElementById('ルート')
);

アクションにパラメータを渡し、カウンターケースを拡張する

このカウンターの例では、ボタンをクリックして 1 を加算または減算する操作を実装しました。ここで、5 を加算または 5 を減算するなど、値を加算または減算する必要があるという新しい要件があります。

これにはアクションにパラメータを渡す必要がある

ビューでは、ボタンは関数をバインドしてパラメータを渡します

関数 Count({count,increment,decrement}) {
    <div> を返す
        <button onClick={() => increment(5)}>+</button>
        <span>{count} 個</span>
        <button onClick={() => 減分(5)}>-</button>
    </div>
}

dispacthがアクションを実行するとき、パラメータを受け取り、それをアクションに渡します。

エクスポート const increment = payload => ({type: INCREMENT, payload})
エクスポート const decrement = payload => ({type: DECREMENT, payload})

リデューサーでパラメータを受け取り、それに応じて処理する

エクスポート デフォルト (状態 = initialState、アクション) => {
    スイッチ(アクションタイプ){
        ケースINCREMENT:
            戻る {
                カウント: state.count + action.payload
            }
        ケースデクリメント:
            戻る {
                カウント: state.count - action.payload
            }

        デフォルト:
            状態を返す
    }
}

オリジナルURL: https://kspf.xyz/archives/10/

これで、React で Redux を使用してカウンターケースを実装する方法についての説明は終わりです。React Redux カウンター実装に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • React プロジェクトで Redux を使用するエレガントな方法
  • React Reduxミドルウェアの使い方を簡単に紹介する
  • React プロジェクトで Redux をエレガントに使用する方法の詳細な説明
  • ReactNative での Redux アーキテクチャの使用の概要
  • React/Redux アプリケーションで Async/Await を使用する方法
  • 1 つの記事で React における Redux の初期の使用を理解する

<<:  MySQL の完全なデータベース バックアップ データを使用して単一のテーブル データを復元する方法

>>:  オペレーターが知っておくべき 18 個の Nginx プロキシ キャッシュ構成のヒント (どれを知っていますか?)

推薦する

mysqldumpデータエクスポートの問題に関する詳細な議論

1. mysqldump の使用時にエラー (1064) が報告されます。これは、mysqldump...

jsのイベントループ機構の解析

序文ご存知のとおり、JavaScript は本質的にシングルスレッドですが、ブラウザは非同期リクエス...

Vue プロジェクトで axios リクエストを使用する方法

目次1. インストール2. カプセル化に問題はない3. ファイルを作成する4. アドレス設定をリクエ...

Linuxシステムでノードプロセスを実行しているが、プロセスを強制終了できない問題を解決します

まず、Linux システムで実行されているノード プロセスはプロセスを強制終了できないことを紹介しま...

時系列転位修復ケースを実装するSQL

目次1. 要件の説明2. アイデアの概要1. 延長を要求する2. アイデアの概要3. SQLコード1...

VUE+Express+MongoDBのフロントエンドとバックエンドの分離によるノートウォールの実現

付箋紙の壁シリーズを実現しようと思っています。シンプルなものはシンプル、複雑なものは多機能です。開発...

MySQL truncate table ステートメントの使用

Truncate table ステートメントは、テーブル内のすべてのデータを削除/切り捨てるために使...

Vue が配列の変更を監視できない問題の解決方法

目次1. Vueリスナー配列2. vueが配列の変更を監視できない状況1. Vueリスナー配列Vue...

デザイン参考 WordPressウェブサイト構築成功事例

これら 16 のサイトはそれぞれ注意深く読む価値があり、どのサイトでも推奨されている Web サイト...

MySql 組み込み関数の自習知識ポイントまとめ

文字列関数文字ascii(str)のASCIIコード値をチェックし、strが空の文字列の場合は0を返...

Vue3でアイコンを使用する2つの例

目次1. SVGを使用する2. fontAwesomeを使用する3 ソース4 結論テクノロジースタッ...

MySQL のロックの仕組みと使用法の分析

この記事では、例を使用して MySQL のロック メカニズムと使用方法を説明します。ご参考までに、詳...

アバターと国旗の統合を実現する1行のCSSコード

今日は建国記念日で、誰もが祖国の誕生日をお祝いしようとしています。毎年この時期になると、WeChat...

MySQLはカスタム関数を使用して親IDまたは子IDを再帰的に照会します

背景: MySQL では、レベルに制限がある場合、たとえば、ツリーの最大深度を事前に決定できる場合、...

MySQLの日付加算と減算関数の詳細な説明

1. 追加時間()指定した秒数を日付に追加する select addtime(now(),1); -...