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 プロキシ キャッシュ構成のヒント (どれを知っていますか?)

推薦する

Linux 時間サブシステムの時間表現例の詳細な説明

序文Linux カーネルでは、元のコードとの互換性を保つため、または特定の仕様に準拠するため、また現...

MySQLデータ復旧のさまざまな方法の概要

目次1. はじめに2. 直接回復2.1 mysqldumpバックアップの完全リカバリ2.2 xtra...

Vue3+スクリプト設定+ts+Vite+Volarプロジェクト

目次Viteを使用してvue + tsプロジェクトを作成するVue 3の3つの構文オプションAPIコ...

ウェブページデザインのための4つの実践的なヒント

関連記事: Web コンテンツ ページを作成するための 9 つの実用的なヒント<br />...

Mysql で group_concat の長さ制限を変更する方法

MySQL には、「group_concat」という関数があります。通常の使用では問題がないかもしれ...

cmd と python での MySQL の一般的な操作についての簡単な説明

環境設定1: MySQLをインストールし、MySQLのbinディレクトリを環境変数に追加する環境設定...

MySQL ロックの知識ポイントのまとめ

ロックの概念①. 現実世界では、鍵は外の世界から身を隠したいときに使う道具です。 ②. コンピュータ...

NginxはGzipアルゴリズムを使用してメッセージを圧縮します

HTTP圧縮とは場合によっては、比較的大きなメッセージ データがクライアントとサーバー間で送信され、...

Vueでaxiosをカプセル化するいくつかの方法

目次ベーシックエディションステップ1: Axiosを構成するステップ2: リクエストをカプセル化する...

MySQL で中国語を入力するときに発生するエラー 1366 の解決方法

MySQL で中国語を入力すると、次のエラーが発生します。エラー 1366: 1366: 行 1 の...

Vueは移動可能なフローティングボタンを実装します

この記事の例では、どこにでも移動できるフローティングボタンを実現するためのVueの具体的なコードを共...

Ajax responseText による JSON データの解析のケース スタディ

ajax 処理後にサーバーから返される responseText が JSON データであるという問...

MySQLで日付を比較する方法の詳細な説明

データ型が datetime であるフィールド add_time を持つテーブル product が...

WebpackはTypeScriptコードをパッケージ化するためのスキャフォールディングを構築します

フォルダを作成するディレクトリ構造: dabaots npm init -yを初期化して packa...

Docker で Confluence をデプロイするための完全な手順

Confluence は有料ですが、クラックして使用できます (購入が推奨され、正規版がサポートされ...