お知らせ
以下の内容は出所の内容そのままでございます。私からの修正は行なっておりません。
記事の作成スタイルが原文と異なる場合がございます。(コードブロックや文言の強調、色付きなど)
⚠️⚠️⚠️以下内容の出所は以下のリンクになります。⚠️⚠️⚠️
原文 : https://leerob.io/blog/react-state-management?fbclid=IwAR2jI5klYjGLoJXuOLcMIctncQuniOgMQIwmwEIb65T-C3x0-erc86Jvu00
韓国語版の原文 : https://velog.io/@cadenzah/history-of-react-state-management
以下全ての内容は韓国語版の原文を日本語に翻訳した内容です。
はじめに
この記事はPast, Present, and Future of React State Managementを翻訳した記事でございます。
韓国語版を基準で日本語に翻訳しております。
原文は2021年に作成されており、原文内容をそのまま日本語に翻訳するのが目的なので、情報の最新化は行なっておりません。
state管理に関する記事を作成中に、原文より良い内容の記事はなさそうと思ったので出所を明らかにして翻訳しました。
Reactのstate管理に関して軽く知っていこうと言う気持ちで作成する記事でございます。
この記事はPast, Present, and Future of React State Managementを翻訳した記事です。
自然な文脈のため意訳を行う場合がございますが、原文の内容や意味を自然にお伝えするようにしております。
翻訳中に英語の方が自然な場合は原文の英語をそのまま記載しております。
私からの補足説明は引用文に作成するか、括弧内に訳者注文を通して付けました。
React state管理の過去、現在、そして未来
Reactは2013年5月に初めて公開されました。 UIはstateに対する関数だという考え方が、Reactが提示したパラダイムの転換でした。 コンポーネントのstateが与えられれば、Reactはコンポーネントがどのような姿を持つべきかを決定できるようになるということです。 Reactはこのようなstateに対するアイディアを根幹としています。 しかし、stateはこれまでReactアプリケーションを開発する際に最もややこしい部分の一つとされてきました。
Reactの状態管理ツールはまるで荒れた工具ベルトのようなものですが、いつどんな工具を使うべきなのか誰もがよく知っているわけではありません。 この文では、ステータス管理の過去、現在、そして未来について説明しながら、皆さんのチーム、プロジェクト、または組織で正しい決定を下すのに役立てたいと思います。
用語
始める前に、まず主に使われる用語を理解しておいて次に進まなければなりません。 以下の用語は公式的なものではありません。 いくつかのさまざまなバリエーションが存在しますが、その根底にある根本的なアイデアは同じです。
UI state : アプリケーションの相互作用部分制御に使用されるstate(e.g.ダークモードトグル、モーダルなど)
サーバキャッシュのstate:サーバの応答に対するstateで、クライアント側にキャッシュしておいて素早くアクセスするのに使用(e.g.API呼び出し結果を保存し、その後、複数の場所で活用)
フォームstate:フォームに対する様々なstate(e.g.ローディング中、転送中、無効化、有効性検査、再試行など)。 制御&非制御フォームstateも存在する。
URL state:ブラウザが管理するstate(e.g.商品をフィルタリングした後、それをクエリー因子に保存し、その後ページを更新してもフィルターされた商品が同じページに表示)。
state機械:時間の経過に伴うstate変化に対する明示的モデル(e.g. 信号機の色は緑→黄→赤の順に変化するが、緑→赤に変化することはない)。
過去
Reactのコンポーネントモデルは、再利用と分解が容易なアプリケーションを開発できるようにしてくれました。 各コンポーネントは固有のローカル ステータスを持ちます。 ウェブアプリケーションがますます複雑になるにつれて、コンポーネント間でロジックを簡単に共有できる新しいソリューションが登場するようになりました。
年表
時間の経過とともに、state管理がどのように進化したかをより簡単に理解できるように、Reactの有名なstate管理ソリューションをおおよその時間順にまとめてみました。 以下のリストはUIstateの管理に重点を置いています。 詳しい説明は書いていませんが、文脈を理解するには十分でしょう。
- 2013 - React登場
- 2014 - Flux (様々なライブラリが登場)
- 2015 - Redux
- 2016 - MobX
- 2018 - Context
- 2019 - Hooks (+ React Query, SWR)
- 2019 - Zustand
- 2019 - xState
- 2020 - Jotai, Recoil, Valtio
- 2021 - useSelectedContext
上記の年表に書かれた内容だからといって、必ず学ぶ必要があるわけではありません。 これについては後程詳しく説明します。 それでは、React state管理の歴史について本格的に話してみましょう。
Redux
Redux は本来、2014年にFacebookで初めて提案したパターンである"Fluxアーキテクチャ"の実装体として作られました。 Reduxは2015年に登場し、その後急速に関心を集め、Fluxからインスピレーションを受けたものの中で最も有名なライブラリーとなりました。 Reduxのツールとライブラリ生態系はUIstateとサーバーキャッシュstateの管理を統合しました。 Reduxは今でも最も有名で広く使用されています。
サーバーキャッシュステータス
Reactが登場した初期には、ほとんどのstate管理ツールの主な機能は、APIから取得したデータをアプリケーション全体にわたって使用できるようにキャッシングすることでした。 サーバキャッシュstateを管理するための簡単で広く通用する方法が特になかったため、ReactユーザーはReduxのようなライブラリに大きく頼るしかありませんでした。
React Hooks が発表されたことで、共有されたHooksにロジックを統合することがはるかに容易になり、アクセシビリティが向上しました。 SWRとReactQuery のようなライブラリが登場し、この問題を重点的に解決しました。
「ただサーバーキャッシュのstateだけのために別途のライブラリを使用する理由があるのでしょうか?」と反問する方もいるかもしれません。 そうですね、キャッシュの作業はややこしいです。 サーバーのキャッシュstateはUI stateと異なるタイプの問題を扱います。 サーバーのキャッシュstateに関するライブラリが扱う問題を簡単に整理してみました。
- 周期的なポーリング
- フォーカス時に再検証
- ネットワーク回復時に再検証
- 地域的state変更(オプティミスティックUI)
- 向上した Error Retry
- ページネーションとスクロール位置の復旧
訳者cadenzah注 : 上記のリストは、SWR公式文書のIntroductionから一部抜粋してきたものです。
これらの機能を直接実装したいですか? 多分違うと思います。
React Context
v16.3 アップデートにより、React Contextはコンポーネント間でロジックを共有できるファーストパーティソリューションを提供することになりました。 また、これにより、重ねられた複数のコンポーネントにpropsで値を伝達するコード(i.e."Prop Drilling ")を防止することができるようになりました。
訳者cadenzah注:上記の段落にリンクしたPropDrillingに関連したブログの文は翻訳本があり、原文 を代わりにリンクしました。
React Contextは、それ自体ではステータス管理ではありません。 しかし、React Contextはuse ReducerのようなHooksと一緒に使用すると state管理ソリューションとして活用できます。 この組み合わせはUIstateに関する多くの共通事例を解決することができます。
訳者cadenzah注:上記の段落にリンクしたReact ContextとHooksに関するブログの文は翻訳版があり、原文 を代わりにリンクしました。
現在
2021年現在、Reactでstate管理を扱うには多様な方法が存在します。コミュニティが成長して様々なタイプのstateに触れることになったことによって、特定問題状況の解決に重点を置いた細部的なライブラリが多く開発されました。
state機械
Switch構文を思い浮かべてみましょう。 もしstateの値があるcaseに対応するなら、これに対するコードが実行されます。 限られた数の場合が存在します。 これは最も単純な形態のstate機械であり、stateの明示的なモデルです。
case state === 'loading':
// ローディングスピナー表示
break;
case state === 'success':
//成功メッセージを表示
break;
default:
//エラーメッセージ表示
}
有限state機械とstate表は基礎的なコンピュータ科学の概念であり、特にReact に限定されたものではありません。 別のサードパーティ ライブラリがなくても、useReducerをステータス マシンに変換できます。
ステートマシンは、データベース、電子、自動車など、すべての分野に適用されています。 React生態系におけるstate管理の概念がますます進化するにつれて、このような古い概念が現代のstate管理問題を解決できるということを悟るようになりました。 ステータス マシンは、フォーム ステータスの問題を解決するために最も広く使用されています。
有限stateマシンを使用すると、アプリケーションまたはコンポーネントが持つことができるstateの数が有限に決定されます。 実務では、ステータス マシンを使用するとエッジ ケースを検討して定義することができ、バグを見つけることが容易になります。 これに関する詳しい情報をご希望の場合は、xState に関する文書をご確認いただくか、この講座をお勧めします。 また、ステータス マシンをオンライン上で視覚化を使用することもできます。
Zustand, Recoil, Jotai, Valtio, まったく!
React ステータス管理ライブラリがこれほど多く存在する理由は一体何でしょうか?
Figma(または他のデザインツール)を一度回想してみましょう。見れば制御ツールバーらが複数あるが、これを操作すれば当該ツールバーの外の他の要素に影響を及ぼすか、コンポーネントが描かれる位置などが異なります。
お気づきかと思いますが、この規模のアプリケーションでは複雑なstate管理ソリューションが必要です。 優れたユーザーエクスペリエンスのためには、パフォーマンスとフレームレートが非常に重要であり、したがって、リレンダーの視点と方法に対する制御権を持つ必要があります。 このように独特な事例によって、state管理という領域で多様な探検が続くのです。
Daishi Kato によると、ライブラリ間の違いは以下のように簡単に要約できます。
- Valtioは値を直接変更する式(Mutation-style)のAPIを提供するための委任者(Proxy)を使用する。
- Jotaiは"計算された値"と非同期アクションに最適化された。
- Zustandはモジュールのstateに特に重点を置いた非常に軽量なライブラリである。
- Recoilはデータフローグラフを使用した実験的なライブラリである。
訳者cadenzah注 : 各ライブラリの公式ページまたはGithubリンクは下記の通りです。
Valtio: Makes proxy-state simple for React and Vanila
Jotai: Primitive, flexible state management for React
Zustand: Bear necessities for state management in React
Recoil: A state management library for React
state、構造が複雑として必ずサードパーティのライブラリを使用しなければならないわけではありません。ReactとJavaScript万で始めてどこまで可能か見るのも一つの方法です。最適化にstate管理ライブラリが必要であれば、当該場合で関連指標(e.g.フレーム率など)を追跡や測定してみて、問題が解決されるかを確認すればいいです。
確実に必要ない状況なら、ライブラリをあえて使用しなくてもいいです。
immutable state
もう 1 つの論争の的は、可変およびimmutableのstateについてです。 ここには正解がなく、意見があるだけです。 バニラJavaScriptでstate管理を行っているなら、可変stateで管理している可能性が高いです。 変数を初期化し、その後は該当変数を新しい値と同じ値にするのです。 letかconstかについての論争また存在します。
immutable stateはReactで大きな有名になりました。 不変性を主張する人々は、ステータス管理ソリューションがステータスを直接変更できるようになると、これはより多くのバグにつながると述べています。 可変性を主張する人々は、不変性がむしろより複雑性を高めるだけだと反論します。 直接操作は、間接操作に比べて常に安全ではありません。 利便性とリスクの間の二者択一の状況であり、選択は皆さん、そして皆さんが属しているチームの役割です。
Immer のようなソリューションを使用すると、コードは可変的に作成されますが、実行は不変的に行われます。 つまり、現在の状stateに対する委任者(Proxy)に該当するstate草案に変更事項を優先適用することです。 変更が完了すると、該当state草案になされた変更事項に基づいて、Immerは次のstateを生成します。
URL state
Amazonと同じ電子商取引のウェブサイトを開発するとしてみましょう。Reactの書籍を検索して、星印が4以上の項目だけをフィルターします。このstateはクエリー因子として維持されてブラウザが管理します。ページをリロードしても同一の項目たちを見ることができます。該当URLは他の人と共有することができるし、その人たちも同一結果を確認することができます。
また、他のおもしろい例示はNomad Listです。ブラウザURLstateをデータ関数に変換することができます。さらに人が読める形式のURLを構成することもできます(これはGoogleが好む形式でもあります)。
未来
大型アプリケーションの場合、単にContextだけを使用したstate管理ソリューション(e.g.useReducer)では、過度なリレンダリング問題が発生する可能性があります。 Context値が変更されると、useContextを使用するすべてのコンポーネントではリレンダリングが行われます。 そうするとUIの相互作用が遅くて、どもるように感じます。 肉眼で確認できない場合、React Dev Tools を使用してリレンダリングを確認することができます。
ReactチームはContext使用時の性能問題を適切に防止するためのuseSelectedContext Hookを紹介しました。2019年7月にこれに対するRFCが公開され、2021年1月基準でFeatureフラグがついて開発が順調に行われています。このHookを使用すれば、Contextの"一部"だけを選択し、当該一部分が変化した時だけリレンドが行われるように作ることができるようになります。
既にリレンダリング性能を最適化できる他の方法(e.g.useMemo)が存在しますが、Contextのためのファーストパーティソリューションが出てくるとより良いでしょう。useContextSelectorというコミュニティベースのライブラリも存在し、同様のアプローチをとります(Demo)
JotaiとFormik 3はそのライブラリを内部で活用しています。 useSelected ContextがReact標準ライブラリに含まれると、外部ライブラリの使用による複雑性とコードバンドルのサイズが小さくなり、より多くの性能関連オプションを基本的に提供できるようになります。
長期的には、Reactはどのコンポーネントをリレンダリングすべきか、自分で特定できるようになるでしょう("Auto Memoization").
ステータス管理ツールの選択肢
以下のリストは、すべてのライブラリを示しているわけではありません。 この文はオープンソースでもあるので、下記のリストに同意しなかったり、何か間違っていると感じたらPRを作成してください。 できれば、あなたが属しているチームとチーム内の開発者が好むものを選択してください。 Reduxに不満はありませんか? じゃあ、そのまま使ってください!
フォームstate
経験 | 学習意欲 | プロジェクト/チーム規模 | 解決策 |
---|---|---|---|
初級 | 低 | 小型 | useState |
初級 | 中間 | 中間,小型 | フォームライブラリー(Formik, Final Form) |
初級 | 高、中間 | 大型 | テックリーダーと相談 |
中級 | 低 | 中間、小型 | フォームライブラリー(Formik, Final Form) |
上級 | 中間 | 中間 | state機械 |
上級 | 高い | 中間 | state機械 |
上級 | 高い | 大型 | state機械 |
UI state
経験 | 学習意欲 | プロジェクト/チーム規模 | 解決策 |
---|---|---|---|
初級 | 低 | 小型 | useState |
初級 | 中間 | 中間、小型 | useContext + useReducer |
初級 | 高、中間 | 大型 | テックリーダーと相談 |
中級 | 低 | 中間、小型 | Redux Toolkit |
上級 | 中間 | 中間 | useContext + useReducer |
上級 | 高い | 中間 | Jotaim, Valtio |
上級 | 高 | 大型 | Recoil(またはGraphQLを使用する場合、Relay |
サーバーキャッシュステータス
経験度やチーム規模にかかわらず、SWRとReact Query が完璧なソリューションです。 どちらも満足すると思います。 GraphQLを使うなら、Apollo を既にご存知だと思います。
That's all, folks!
Reactでのstate管理は過去8年間で大きく進化してきました。 大規模なウェブ アプリケーションの開発において、最もややこしく、微妙な内容の 1 つです。 stateの多様なタイプとそれぞれのトレードオフを理解してこそ、これを基に情報に基づいた決定を下すことができます。 この文が役に立つことを願って、読んでくださってありがとうございます。