Skip to content

【Redux入門】 React + Redux の考え方を理解する

最近 React で SPA ( Single Page Application ) を作る際に、Redux という言葉がよく出てきます。

Redux の入門記事を検索してみると、サンプルコードが載っている記事はたくさん見つけることができるのですが、そもそも Redux がどういうものなのか、という点について紹介している記事が少ないように感じたので、今回書いてみることにしました。そこでこの記事では、Redux とは一体何なのか、Redux で何ができるようになるのかという点について、整理していきたいと思います。

前提:SPA と 『状態』

まず SPA を作るうえで必ずポイントとなるのは、アプリケーションの『状態』をどう管理、把握するかということです。『状態』というのはアプリケーションが持っている情報のことで、例えばTODOリストのように何かの一覧を表示するアプリケーションであれば、

  • 絞り込み条件は何か
  • 並び順は何か
  • 表示されているテキストは何か

といったような情報が『状態』にあたります。こういった『状態』は、React や Redux では “State” と呼ばれており、そして、この『状態』の管理の設計として注目されている思想の1つが Redux というわけです。

それでは、なぜ Redux が注目されているのかという点について、私の個人的なフロント実装の歴史を振り返りながら、紹介していきます。

jQuery の時代

私が最初に経験したフロントエンドの実装はjQuery を使ったものでした。この時代、例えばタブによるコンテンツ切り替えを行うコンポーネントの処理は、次のような流れで実装していました。

  1. タブがクリックされる
  2. クリックされたタブ以外のタブから “is-selected” を削除し、クリックされたタブに ”is-selected” を付加する
  3. show() されていたコンテンツを hide() し、クリックされたタブに対応するコンテンツを show() する

このように、jQuery を使った実装ではタブやコンテンツについているクラスやデータ属性、CSS に基づいて処理が書かれていました。アプリケーションの状態を示す情報が各 DOM に分散している状態と表現することができます。

さらに実際には、コンポーネントがページに複数存在した場合や、コンテンツ内にフォーム要素が含まれている場合、ページロード時の表示なども考慮する必要があるため、より複雑にクラスや属性を張り巡らせることになり、アプリケーションにどんな情報があるのか、コンポーネントが動作するために必要な情報はどれなのか、コンポーネントがアプリケーションをどう変更するのか、といったことの把握に多くの労力が必要でした。

また、情報を DOM が持っていること自体も大きな問題でした。というのも、DOM は誰もが変更できるものなので、他コンポーネントのスクリプトやユーザーの操作と競合して不具合が発生するリスクが常につきまとっていたからです。

React の時代

React の詳細については割愛いたしますが、React を利用することで、これまで DOM に分散していた情報をコンポーネントごとに定義される JavaScript オブジェクトで管理できるようになりました。この JavaScript オブジェクトを ”State” といいます。

State によって、そのコンポーネントにどんな情報が必要なのか把握しやすくなりました。また、コンポーネント同士を疎結合に作ることもできるようになったので、コンポーネント同士で State が競合する危険性もなくなっています。それだけではなく、React では State は setState() 関数を使わないと更新できないので、ユーザーの操作で直接変更される危険性もなくなりました。

このように React を利用することによって、jQuery の時代に存在していた 『情報』の管理に関する課題は大きく改善されましたが、State はいまだに各コンポーネントに分散している状況でした。これではアプリケーションが複雑になればなるほど State の存在箇所が増えていってしまい、把握、管理が難しくなっていってしまいます。

React の時代(2)

State が各コンポーネントに分散するという課題を解決するために、運用上の工夫をするようになりました。具体的には、全ての State をアプリケーションの最上位のコンポーネントに持たせ、子孫コンポーネントは親コンポーネントから渡された Props だけを使って実装する、というルールを設定しました。

これにより、State やその更新メソッドを最上位コンポーネントに一元化することが可能になり、アプリケーションのすべての State と、その State がどう変更される可能性があるのかという情報を一か所にまとめることができるようになりました。

このルールを設定したことで、アプリケーションに存在する State とその更新パターンを一か所にまとめることができるようになりましたが、あくまで運用上のルールにすぎませんでしたので、きちんと実装レベルで実現するための仕組みが欲しいと思っていました。

React + Redux の時代

State とその更新メソッドの保持をアプリケーションの最上位のコンポーネントにだけ許可する、というルールを実装レベルにまで落とし込むため、Redux を利用するようになりました。

Redux とは

Redux では Store、Action という2つが大きな役割を持っており、Store は State の管理者という役割、Action は State の更新パターンを定義する役割を持っています。

State を管理する『 Store 』

Redux を理解するうえで最も重要なのが Store です。

Store は唯一 State を操作できる存在であり、アプリケーションに1つだけ存在します。そして React などで作られたコンポーネントは、この Store の提供するメソッドを利用することによって、間接的に State の参照や更新を行うことになっています。

たとえると、State は大変なものなので誰でも変更できる状態にはしておかずに、Store という管理者をたてて保管する、というようなイメージです。利用者(コンポーネント)が直接 State を操作できないようにしておき、必要なときには管理者(Store)に申請を出して State の情報を取得、更新するというようなイメージですね。

State の更新パターンを定義する『 Action 』

Action は、State の更新パターンのことです。管理者のたとえでいうと、利用者が管理者に出す申請書がこれにあたります。

State に対して行えるすべての更新が Action として管理されるので、アプリケーションに発生しうる更新を把握しやすくなります。また、あらかじめ定義した Action に基づいて State を更新するというフローが確立されることで、予期せぬ更新を防ぐことができるようになります。

たとえば申請書の存在しない申請はそもそもあげることができないように、「TODOリスト全削除」という Action を用意していなければ、何かの拍子に TODO が全削除されてしまった、というような予期せぬ更新を防ぐことができるようになります。

State の更新を実装する『 dispatch() 』『 Reducer 』

管理者のたとえでいうところの申請をあげる行為が、dispatch() です。この dispatch() は引数に Action をとり、この Action に基づいて Store が State を更新します。

そしてこのとき、Store がどのように State を更新するのか定義したものが Reducer です。Store にとって Reducer は State の操作マニュアルのようなものですね。

なお、Store は他にも getState(), subscribe() というメソッドを提供をしており、State を取得したいときには getState()、State 更新時に実行する処理を定義するときには subscribe() を使います。ライブラリによっては意識しないかもしれませんが、subscribe() に画面の描画処理を定義して、State が更新されたら画面も更新されるように実装することが多いです。

まとめ

ここまで、私なりの Redux のイメージを紹介させていただきました。Store が管理者、Action が申請書、Store.dispatch(Action) が申請書の提出、Reducer は State 操作マニュアル、というイメージが個人的にしっくり来たので紹介させてもらいました。Redux とはいったいなんなのか、SPA を作る上で大切な State をどのように管理する思想なのか、といったことが伝わっていれば幸いです。

なお、実際のソースや開発環境については改めてまとめたいと思っています。

また、Redux にも Store や Action が肥大化しやすいというような課題は残されているので、まだまだ設計手法は進歩していきそうです。

最後に、各時代の状況をまとめておきます。

  • jQuery の時代
    • State の一元化:×
    • State の更新の管理:×
  • React の時代
    • State の一元化:△
    • State の更新の管理:×
  • React の時代(2)
    • State の一元化:〇
    • State の更新の管理:×
  • React + Redux の時代
    • State の一元化:〇
    • State の更新の管理:〇

関連記事書きました。
Node.js を使わない React + Redux 最速環境構築

Comments are closed.