React(SPA)で作っていた個人開発プロジェクトをNext.js(App Router)へ移行しました。
その過程で「これは意識しておいてよかった」「初期にやってしまって失敗だった」など色々感じた点をまとめます。これからReactからNext.jsへ移行する方の参考になれば幸いです。
前提
もともとReact + Vite構成で、検索・保存・編集といったUI中心のSPAとして実装していました。Next.jsへは、SEO対応とURL設計の見直しを目的に移行しています。
移行時にまず意識したことは以下です。
- React時代のコードをそのまま持ち込まない
- 動く最小構成を作る
- ページとコンポーネントの責務を混ぜない
画面の意味をどこで表現するかを見直す
React(SPA)では、画面が何を表示しているかを state によって決める構成を採用していました。
画面の意味はコンポーネントの内部状態として管理され、URLは必ずしもその内容を直接表していません。
一方、Next.js(App Router)では画面の意味を URL で表現する設計が自然になります。URL がそのまま「今どんな画面を見ているか」を示しているのでpage は URL に基づいて表示内容を決定します。
一時的なUIの状態だけを state に残し画面の意味そのものは URL が担う、という役割分担を意識するようになりました。
pageとcomponentの役割を明確にする
移行初期はReact時代と同じ感覚でpageにUI・ロジックも書いてしまいがちだったので、次のように分けました。
- page
- URLに関係するstate
- データ取得
- 画面構成の決定
- component
- 見た目
- ユーザー入力の通知
componentは「どう動くか」ではなく「どう表示するか」だけを担当させました。
propsを減らすことを目的にしない
移行中、propsが多すぎるから減らした方が良いかもしれないと思いましたがこれは目的を見誤りやすい点でした。
- propsが多いこと自体は問題ではない
- 問題なのは親の実装手順を子に渡していること
- UIとして意味のある入力だけをpropsにする
propsを減らすのではなくpropsが情報なのか or 配線なのかを見るようにしました。
具体的なコードによる比較
例として検索フォームのコードを挙げます。
React(SPA)時代は、SearchFormに多くの役割を持たせていました。
Before(React)
<SearchForm
inputRef={inputRef}
formRef={formRef}
input={input}
onInputChange={(e) => setInput(e.target.value)}
onSearch={() => handleSearch(inputRef)}
isLoading={isLoading}
error={error}
/>
Next.js移行後は、SearchFormを入力UIに限定しました。
After(Next.js移行後)
'use client'
export default function SearchForm({
value,
onChange,
}: {
value: string
onChange: (value: string) => void
}) {
return (
<form onSubmit={(e) => e.preventDefault()}>
<input
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="Search a word"
/>
</form>
)
}
SearchFormは入力を表示し、変更を通知するだけのコンポーネントになります。検索処理やURL遷移はpage側に任せます。
refsや実装詳細を子に渡さない
React時代は、refやコールバックを子に渡す設計でも違和感がありませんでした。しかしNext.jsではこれが構造を分かりにくくします。
- refはpage側で完結させる
- 子は結果だけを受け取る
- 子は親の関数の存在を知らない
これだけでコンポーネントの読みやすさが大きく改善しました。
最初から完成形を目指さない
移行直後は「設計をきれいにしなければ」と思いがちですが、これはかなりの罠でした。
- まず入力して遷移できる
- 次にURLから値を取得できる
- 最後にデータ取得をつなぐ
一段ずつ動作確認することで、Reactとの違いを体感しながら進められました。
まとめ
ReactからNext.jsへの移行は単なるフレームワーク変更ではなく、考え方の切り替えが必要でした。
- state中心からURL中心へ
- 巨大コンポーネントからpage主導へ
- propsは情報として渡す
まだまだ改善の余地はありますが、これらを意識することで少しずつNext.jsらしい構成に自然に近づいている気がしています。
