React Developer Roadmap 2024 を眺める
はじめに
React Developer Roadmap 2024 を眺めつつ筆者の独り言を書く記事です。筆者の React 歴は 3 年ちょっとです。
Visit JavaScript Roadmap
React のロードマップは JavaScript の勉強が最初。Promise を基本とした非同期処理やクロージャ周りを理解しておくと、React への理解も更に深まった記憶がある。
非同期周りはこの本に助けられた。
CLI Tools
- Vite
- Create React App
新規に CSR の SPA を作る場合 Vite 一択だと思う。理由は、設定簡単 + 早い + 拡張性 ◎ + エコシステムが大きい。Vite は SSR もできるがライブラリ作者向け。
(宣伝) Vite を使用した環境構築方法は先日記事にしました。
なぜ Create React App が使われなくなりつつあるのか下記記事に詳しく書かれている。
Components
- Class Components
- Functional Components
- Component Basics
- JSX
- Props vs State
- Conditional Rendering
- Composition
今の時代、ほぼ関数コンポーネント一択。業務でクラスコンポーネントを書いたことがない...。良くみる UI = f(state)
はまさに React そのもの。「UI は関数 (コンポーネント) にステート (状態) 渡して実行した結果である。ステートが変われば、関数が再実行され、実行結果 (UI) が変わる。」と理解できたとき、React に対する難しい印象が薄れた記憶がある。
JSX × TypeScript はテンプレートエンジンとしてかなり優秀。DSL 系?の Vue や Svelte より React が好きな理由もここが大きい。
ステートを Props で受け取るかコンポーネントで保持するかも重要な話で、コンポーネントのレンダリング回数に直結する部分。単純にそのステートを使うコンポーネントはどれかを考えればいいと思う。
Conditional Rendering は if
とか &&
、三項演算子など使用して、関数 (コンポーネント) が返す JSX を条件によって変えること。注意点としては、num && <p>test</p>
は num
が 数値の 0 だと、画面に 0 が表示されてしまうので、!!num && <p>test</p>
にする必要がある。
Composition は Props としてコンポーネントを渡すこと。children が主な例。React Server Components の登場で children の重要さは更に増している。
Rendering
- Component Lifecycle
- Lists and Keys
- Render Props
- Refs
- Events
- High Order Components
コンポーネントのライフサイクルは、useEffect
とかコンポーネント直下に console.log
をたくさん入れて理解していった。特に非同期処理とステートの更新処理が組み合わさった時の挙動の理解には時間がかかった記憶がある。
リストとキーについては、リストの要素を削除や並び替えするとき、キーを配列のインデックスにしてしまうと React 的に良くないから、基本的に DB から取得したユニークな値にしましょう、というお決まりコメント。
Render Props は JSX を返す関数を Props に渡すことだが、自分ではあまり書いたことがない。ライブラリとかでたまに見かける。React Final Form とか。
useRef
は DOM へのアクセス以外に、コンポーネントで値を保持したいときに使う。 useRef
or useState
かは、その値が更新されたときにコンポーネントを再レンダリングしたいかで決めればいい。コンポーネント直下に const intervalId: number | null = null
みたいに書いて setInterval
の返り値を代入しているコードをたまに見かけるが、コンポーネントの再レンダリング === 関数の再実行なので、コンポーネント直下に定義した変数はレンダリングの度に初期化される。値が更新しても再レンダリングしたくない & 値を保持したい場合は useRef
を使う。useRef
は裏側で React が値を保存してるので、再レンダリングしても値は初期化されない。
Events は on~
Props に handle~
関数を渡すのがお決まり。onClickButton
と onButtonClick
はどっちが多いんだろう。ブラウザには onvolumechange
みたいなイベントがあるから、onButtonClick
にしている。
High Order Components は可読性が悪いので極力自分では書きたくない。大体はカスタムフックで対応できるはず。
Hooks
- Basic Hooks
- useState
- useEffect
- Writing Custom Hooks
- Common Hooks
- useCallback
- useRef
- useMemo
- useReducer
- useContext
- ...
useState
を使う時は、それが本当に必要なステートかどうかを、自分で書いている時もレビューしている時も意識して見ている。よくあるのは、他のステートから計算できる値を別途ステートして持っているパターン。あとは関係のあるステートなら分けて管理するよりも、オブジェクトなりにして一緒に管理した方がいい場合も多い。同じタイミングでセット関数を呼んでいる場合は一つのステートにまとめられる可能性が高い。
useEffect
についても本当に必要か考える必要がある。値の変化を監視するために使うのは基本的に良くない。というより必要ない。count
という変数が変わったときに処理をしたいなら、count
を更新する関数内で処理をすべき。あと、クリーンアップちゃんと書こう。
Hooks を使った同じような処理が多い場合は、カスタムフックにするとコンポーネントの見通しが良くなりやすい。コンポーネント肥大化してきたなぁ、ロジック多いなぁと思ったらカスタムフックを作るチャンス。
useCallback
と useMemo
について。メモ化したコンポーネントに関数 or オブジェクトを渡すときは当たり前だが、カスタムフックが関数 or オブジェクト を返すときは常に useCallback
、useMemo
を使う、と決めている。それ以外についてはパフォーマンスが問題になってから考える。
useReducer
はあまり使ったことがない。フィールドが多いフォームなどを作る時は useState
よりも便利そうだが、大きめのフォームを作るなら React Hook Form なりを使ったほうが良さそう。
useContext
には正直いい思いがない...。結局状態管理ライブラリが欲しくなる可能性が高い。パフォーマンスを意識するとプロバイダーが何重にも重なってくるし、コンテキスト間の依存関係把握も難しい。ボイラープレートも多め。Recoil
や Jotai
などサクッとグローバルステートを作れるライブラリも多いから、無理してコンテキストで乗り切ろうとしなくてもいいのでは。
他にも標準の Hooks は沢山あるが useTransition
とかは使いこなせていない...。
Routers
- React Router
- Reach Router
Reach Router は使用経験がない。サッと公式サイトを眺めた程度。Github を見たところメンテナンスされてなさそうなため、React Router 一択か。正直ファイルベースルーティングが当たり前になった現代、自分でルーティング処理を書きたくない。Next.js ほどの機能はいらないけど、ファイルベースルーティングとコード分割、プリフェッチだけは欲しいみたいなことがある。Vite でのいいやり方がないか模索中。検証できたら記事にしたい。
と記事を書いていたら Remix の SPA モードというものを知り、良さそうなので試したい。
State Management
- Recoil
- MobX
- Redux / Toolkit
- Zustand
- Context
ここ数年は Zustand の勢いがすごい。JavaScript Rising Stars でも 2021 年 ~ 2023 年 の State Management 部門で 1 位になっている。npm trends の比較に Redux を入れるとダントツすぎて見づらくなるため入れていない。
Recoil は手軽で使いやすい。ただ、メンテナンス面で少し心配があり、新規に Atom 系?を使いたいなら Jotai を選ぶと思う。MobX は使用経験なし。Redux Toolkit は アクションクリエーターとかを自動生成してくれて、Redux のボイラープレートを減らして楽に書ける。
新規開発する場合、Jotai、Redux Toolkit、Zustand から選ぶと思う。あとはチームで相談。
(宣伝) 状態管理ライブラリについては記事にしているので、よければ参考にしてください。
Styling
- Emotion
- Styled Components
- Tailwind
- Material UI
- Mantine
- Chakra UI
- CSS Modules
ゼロランタイムの CSS in JS がまだ候補にないのが残念。今後はゼロランタイムが主流になっていくと予想している。筆者は vanilla-extract 推し。
スタイリングは CSS と JS を近くで書きたい派と分けたい派があると思う。筆者はどちらかというと後者。後者の代表は CSS Modules だと思うが、TypeScript との相性や補完が効かないなどイマイチだった。vanilla-extract は型が効く CSS Modules だと聞けば良さがわかると思う。
CSS と JS を分けたい理由として、JSX を見た時にスタイリングのコードが多いと、DOM の構造とイベントハンドラの結びつきを理解するまでに時間がかかる、というのがある。React 的なコードと見た目は分けたい。
Styled Components は良く使うが、スタイルを当てたタグなのか、React コンポーネントなのか見た目ではわからない。定義元を参照する必要があるという点を不便に感じている。書き方にもよるが、コンポーネントファイルが肥大化しやすいのも微妙。ファイルは 200 行程度に収めるとより見やすくなると思う。
Tailwind はエコシステムがかなり大きくなっているが、まだ肌に合わない感じがある。とはいえ注目は続けたい。shadcn/ui はロードマップにはないが、2023 JavaScript Rising Stars で 1 位になっていて 2024 年は更に注目されそう。
API Calls
- GraphQL
- Apollo
- Relay
- Urql
- REST
- SWR
- react-query
- Axios
- superagent
- rtk-query
データフェッチは React 周りで最も難しい領域だと思っている。まず非同期そのものの難易度が高い。最初に Promise の基礎学習は必須だと考えている。その上、考える項目が非常に多い。
- どこでフェッチするのか
- サーバーサイド
- クライアントサイド
- いつフェッチするのか
- ビルド時
- リクエスト時
- インクリメンタル
- ロード中かどうかは誰か管理するのか
- isLoading みたいな自前のステート
- SWR、TanStack Query のようなライブラリ
- Suspense
- Suspense を使う場合は、境界はどこか
- Suspense をラップした機構 ( Next.js の loading.tsx など )
- エラーハンドリング
- isError みたいな自前のステート
- SWR、TanStack Query のようなライブラリ
- ErrorBoundary
- ErrorBoundary を使う場合は、境界はどこか
- Suspense をラップした機構 ( Next.js の error.js など )
- 取得したデータの保持はどこでするのか
- リクエストの重複対応
- キャッシュ
- 認証
- ウォーターフォール問題
- Next.js の fetch のようなフレームワーク独自の仕組み
- ...
この中でもキャッシュ戦略が特に難しい。自分の理解もまだまだだと感じでいる。UX の向上にはキャッシュは重要だが、ミスも起きやすい。Next.js のキャッシュ周りのドキュメントを読み込むあたりから始めたい。
ライブラリに関しては、個人でも業務でも TanStack Query (React Query) を多少触る機会があったが、やはり使いやすい。2024 年はより注力したいと思っている。
Testing
- Jest
- Vitest
- React Testing Library
- Cypress
- Playwright
Vitest の体験がすごく良い。TypeScript の設定も必要なし。Jest と同じような API なので、最悪 Jest に戻れる。Testing Library 系は @testing-library/react
と @testing-library/user-event
、@testing-library/jest-dom
を使うことが多い。Cypress は昔手元で少し動かした程度。Playwright は Puppeteer と比べて使いやすかった。自動待機が優秀。
テストが書きやすいコードは結果として責務が明確で可読性が高い良いコードになりやすい。そのためテスト力を上げることは、React 力を上げることになると思っている。
ただ、React に比べてテストはまだまだ経験が浅いので、どこまで、何を、どの手法でテストするべきなのか、ちゃんと言語化できていない部分がある。2024 年は特にテストに力を入れたい。
Frameworks
- Remix
- Next.js
Remix は Discord をたまに見る & 昔 Getting Started を試したくらいで、直近はあまりキャッチアップできていない。というのも Next.js が一つのフレームワークとは思えないほど話題が多くて、そっちで忙しいというのがある。
React Server Components や Server Actions は賛否両論あるが、自分は賛成?している。ユーザー体験を良くするために、試行錯誤しているのが伝わってくる。Next.js は極力 Static に、極力サーバーでという方針。2024 年は更に React Server Components が他のフレームワークでも採用されデフォルトになり、Server Actions がプロダクションで使われていきそう。
とはいえ、Next.js は簡単なフレームワークではないという認識で、SEO 要求がなく、ネットワーク速度も比較的担保されている B2B 管理画面などでは、CSR の SPA で十分だと思っている。そこはパフォーマンスと複雑度のトレードオフだと思っていて、とりあえず Next.js を採用するとかだと、キャッシュ全無効、ほぼ全てクライアントコンポーネントみたいな状況になりかねなく、Next.js のパワーをフル活用できない。Vite でビルドして CDN にデプロイでよかったのでは?と後悔する可能性がある。
あとは、Next.js が一強になり過ぎている感はある。他の知名度があるフレームワークも、個人ブログなどで採用されているケースはよく見かけるが、本当にプロダクションで使われているの?という感じ。とはいえ Next.js の情報が圧倒的に多いので、Remix などを採用するのは気合がいる...。
Forms
- React Hook Form
- Formik
- Final Form
フォームは UX において最も重要な部分だと思っている。自分の経験上、ユーザーに不満を与えやすいのは初期描画の遅さとフォーム周り。Submit してエラーがあった時フォームがリセットされたり、エラー箇所が分かりずらいとストレスになる。
フォームは愚直に作ると useState
が大量生産されたり、大きな useReducer
が必要になったりすることがあるので、そうなるくらいならライブラリを使ったほうがいいと思う。React Hook Form は単体でもバリデーションできるが、Zod と組み合わせると表現力が上がる。
Mobile
- React Native
やはり React と同じ構文でモバイルアプリ開発ができるのは優秀。ビルド周りとスタイリングに慣れればかなり心地よく開発を行える。API からデータを取得して表示 + 基本的な CRUD とかであれば React Native で全く問題ない。ただ、React と比べるとエコシステムはかなり小さい。基本的な機能はライブラリが充実しているが、マイナーな機能になると、ライブラリがあってもスター数 3 桁みたいな状況が多い。そうなるとメンテナンスされていないことも多く、Java や Objective-C あたりで書かれたライブラリのコードを読むことになる可能性があるため覚悟は必要。あと競合の Flutter がやはり人気で React Native の注目はまだまだ低いと感じる。特に日本では。
今までいくつか React Native でアプリ開発をしてきたが、全て Expo を使用していない。そのため Expo 周りのキャッチアップが遅れている。Expo を使えばより快適に開発ができるのは間違いないはず。Expo はファイルベースルーティングや API Routes の機能もあり React Native 版 Next.js のような立ち位置になっている印象。
あとは React Native で React Server Components がどう使われるかは 2024 年注目している。
Frontend Roadmap
フロントエンド全般のロードマップに続く...
Discussion