Honmushi blog
Reduxについての概要2020/02/14

Reduxについての概要

以前からReact/React NativeにてReduxを利用したアプリを作成しています。

Reduxの概念について説明する機会があったので、簡単にですがまとめておきます。 いったんキーワードベースでの解説としいます。サンプルコード等は少なくしました。

基本的にReduxはstateの管理を一つのストアで集約的に管理するものです。 これを使うことでコンポーネントから一元管理されたstateにアクセスできるようになります。 使わない場合はprops等でやり取りすることになりますね。

概要

  • ドキュメント
  • Store
  • Actions
  • Reducer
  • Connect

ドキュメント

https://redux.js.org/introduction/getting-started
reduxのドキュメントです。基本これのチュートリアルを順番に読んでいくことで理解が進みます。

https://react-redux.js.org/introduction/basic-tutorial
reduxをreactで使うためのライブラリーです。reduxはreact以外のフレームワークでも使えるようで、それぞれに対応したライブラリーを使うことがおすすめされています。 reactに対してはこのreact-reduxが公式でもオススメとされています。

Store

ReduxではアプリケーションのすべてのStateをひとつのオブジェクト「Store」にて管理する。

StoreはgetStoreによりデータにアクセスが可能で、dispatchによってデータの更新を行う。 subscribeによってリスナーを登録することもでき、解除もできる。

データを分割したい場合はStoreを複数つくるのではなくではなくReducerの分割をおこなう。 アプリケーションに対してStoreは1つという決まり。

このStoreにてデータを一元管理すること・できることがReduxの肝心なところ。

Actions

Storeに情報を渡すためのオブジェクト。

オブジェクトでありプロパティとして「type」が必要。 typeの値には定数文字列が推奨されており、文字列リテラルでも良い。 「ActionTypes」としてファイルを切り出して定義しておくのがオススメ。

payloadとしてストアに渡されるデータをまとめて定義することもある。

// Action 純粋なオブジェクト
const addTodoAction = {
  type: ADD_TODO,
  payload: {
    id: ++nextTodoId,
    content
  }
}
;

ActionCreator

引数を受け取りActionを返すメソッド。 これを「dispatch」でStoreに渡すことでStoreの更新を行う。

// これは引数を受けとり、Actionを返すのでActionCreator
export const addTodo = content => ({
  type: ADD_TODO,
  payload: {
    id: ++nextTodoId,
    content
  }
});

Reducer

Storeに渡されるActionに応じて、どのようにStateを更新するのかを定義しておく。
Actionの「type」によって更新内容を切り分ける。

Reducerは前のStateとActionを受け取り、次のstateを返す。 Stateに書き込むのではなく別のオブジェクトを返す。したがって、Stateを直接書き換えてはいけない。 前のStateの中身を展開したものと、更新するパラメータをオブジェクトにしてまとめて返す。すなわち更新後のState。

意図せず未定義のアクションが渡された場合は前のStateをそのまま返す。
一番最初はStateが空なはずなので、Stateの初期値を与えておく。

Reducerでやってはいけない3つのこと

  • 引数に与えられたものを直接書き換えてはいけない
    書き換えるのではなく、新しいStateをつくって返す
  • APIの呼び出しやルーティング処理をしてはいけない
  • 純粋でない関数を呼んではいけない
    dateとかrandomとか

CombineReducer

データ定義や関連するドメインなどで分割して子Reducerを作っておき、合成して親Reducerとして扱うと良い。 Stateの一部を管理するような子Reducerを複数作成して、CombineReducerにて結合するのが良い。

動作としてはDispatchにActionを渡すと、全ての子ReducerにActionを渡して帰ってきた新しいStateを結合しているらしい?。

export default combineReducers({ todos, visibilityFilter });

Connect

Connectを使ってコンポーネントをラップすることでコンテナ化する。 こうしてコンテナ化することで、Storeからのデータ取得やdispatchによるデータ更新を可能にする。

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Component);

mapStateToProps

Connectの1つ目の引数。
Storeにアクセスしてデータを取得する処理を行い、stateをコンポーネントのpropsに渡します。 Storeから必要なデータを取得・変換・編集してコンポーネントのpropsへ渡すことが目的です。

基本的にReduxはStoreに何らかの更新があると、データが再取得され再レンダリングの対象になるようです。

このメソッドを定義しなかった場合はStoreがコンポーネントのpropsに渡される?ようです。 nullとかを渡せば、更新不要なコンポーネントとして定義できるかな。

mapDispatchToProps

Connectの2つ目の引数。
Storeにdispatchして更新するための処理をコンポーネントのpropsに渡します。

コンポーネント内でdispatchを実行してもいいのですが、こちらで定義しておくことも出来ます。 定義しなかった場合はdispatchがコンポーネントに渡されるので、コンポーネント内でpropsのdispatchを実行します。

おわりに

Reduxは理解するのに時間がかかるという話を聞きますが、それほどで難しいものではないです。 時間を取ってドキュメントを見れば簡単に理解できます。大きなフレームワークではなく小さなライブラリーですので。

ドキュメントが英語なのでとっつきにくいかもしれませんが、勉強してみるとおもしろい仕組みです。 コンポーネント間で正しくデータを管理して渡せば、Reduxが無くても実装は可能です。しかし、Reduxを選択肢として使えるととても便利です。

React・React Nativeで実装するに当たって、主要ライブラリの一つだと思いますのでしっかり身につけておきたいです。

  • このエントリーをはてなブックマークに追加