LoginSignup
2
4

More than 1 year has passed since last update.

そのデータ、Reactで管理するか?Reduxで管理するか?

Posted at

はじめに

React × Reduxの組み合わせで開発をする時はデータは基本的に全てReduxのstateで管理してきました。

ところがある日、
ダイアログの表示・非表示を切り替えるためのフラグをReduxのstateに追加した時の話。

TypeScript使ってたのでそのフラグをpropsの型定義に追加、useSelectorで取得してpropsに詰めてコンポーネント間で渡して渡して...と目的のコンポーネントにたどり着かせるまでに、修正量は少ないものの直す箇所がたくさんあってかなり面倒でした。

あれ?
これってReduxではなくReactのuseStateでそのコンポーネントで管理すれば楽じゃないかと思ったのですが、統一性を持たせるためにその時はReduxのstateでやり過ごしました。

どう対処するのが正解だったんだろうと思い、調べて記事にしてみようと思いました。

Reduxベストプラクティス

やはりRedux公式に記載がありました。

「明確な正解」はないとのこと。

原文
There is no “right” answer for this. 
Some users prefer to keep every single piece of data in Redux, to maintain a fully serializable and controlled version of their application at all times. 
Others prefer to keep non-critical or UI state, such as “is this dropdown currently open”, inside a component's internal state.
これに対する「正しい」答えはありません。
一部のユーザーは、アプリケーションの完全にシリアル化および制御されたバージョンを常に維持するために、すべてのデータをReduxに保持することを好みます。
コンポーネントの内部状態内で、「このドロップダウンは現在開いていますか」など、重要ではない状態またはUI状態を維持することを好む人もいます。

まさに今回のケース。

こちらの文章以外に上記リンク先にReduxで管理するのが良い場合の記載が箇条書きされてますが、気になったのはこの一文。

原文
Is the same data being used to drive multiple components?
同じデータが複数のコンポーネントを駆動するために使用されていますか?

同じデータを複数の画面で使っているかってこと?
普段ReduxToolKitのcreateSliceを使ってるのですが、画面ごと専用のslice作っているので画面またいで共有なんてしないはず。。

そもそも画面単位でSliceを作っていたことが正しくなかった

これを読んで解決しました。

原文
Root state slices should be defined and named based on the major data types or areas of functionality in your application, not based on which specific components you have in your UI. 
This is because there is not a strict 1:1 correlation between data in the Redux store and components in the UI, and many components may need to access the same data. 
Think of the state tree as a sort of global database that any part of the app can access to read just the pieces of state needed in that component.
ルート状態スライスは、UIにある特定のコンポーネントではなく、アプリケーションの主要なデータ型または機能領域に基づいて定義および名前を付ける必要があります。
これは、ReduxストアのデータとUIのコンポーネントの間に厳密な1:1の相関関係がなく、多くのコンポーネントが同じデータにアクセスする必要がある場合があるためです。
状態ツリーは、アプリの任意の部分がそのコンポーネントに必要な状態の一部だけを読み取るためにアクセスできる一種のグローバルデータベースと考えてください。

なるほど。画面単位ではなく機能単位でSliceを設計するのが本来あるべき姿。
そうなるとさっきの一文も納得でした。

確かに見直せばこれ1つで良かったなと思うデータがあるので、state設計サボってしまっていたことが浮き彫りになりました。。

入力フォームの管理方法について

公式のよくある質問ページにも気になる記載がありました。
テキストボックスやセレクトボックスなど入力フォーム系の値はどこで持つのか?です。

原文
Based on those rules of thumb, most form state doesn't need to go into Redux, as it's probably not being shared between components. 
However, that decision is always going to be specific to you and your application. 
You might choose to keep some form state in Redux because you are editing data that came from the store originally, or because you do need to see the work-in-progress values reflected in other components elsewhere in the application. 
On the other hand, it may be a lot simpler to keep the form state local to the component, and only dispatch an action to put the data in the store once the user is done with the form.
これらの経験則に基づくと、ほとんどのフォーム状態は、コンポーネント間で共有されていない可能性があるため、Reduxに入る必要はありません。
ただし、その決定は常にあなたとあなたのアプリケーションに固有のものになります。
元々ストアから取得したデータを編集しているため、またはアプリケーションの他のコンポーネントに反映されている進行中の値を確認する必要があるため、Reduxでフォームの状態を維持することを選択できます。
一方、フォームの状態をコンポーネントに対してローカルに保ち、ユーザーがフォームを使い終わったら、データをストアに配置するアクションをディスパッチする方がはるかに簡単な場合があります。

テキストボックスの場合、入力値をstateへ即時で反映させたい場合はonChangeに更新用アクションをセットすればよいし、バリデーションまで終わってからstateへ反映させたい場合はonSubmitにセットすれば良いって感じでしょうか。確かに入力フォームは、React Hook Formでバリデーションかけて使うことが多かったので、後者のパターンでした。

話が若干逸れてしまいましたが、やはりここでも画面ごとに共有する必要がない場合はReduxで管理する必要がないことに触れられています。

まとめ

基本的に

  • グローバル(画面関係なく全体)で使うならRedux
  • ローカル(特定の画面だけ)で使うならReact

で自分の中ではひとまず腑に落ちました。

また、人によってバラバラになる気がするので、チームで開発する時はこの基準を明確にしておくことは大事かと思いました。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4