👎

Next.js App Routerにおける筆者のBad Practiceを振り返る

2025/02/08に公開

はじめに

筆者はもともとReactをメインで利用していたが、Next.js App Routerを利用することになった。
その際にやってしまった初期のBad Practiceを振り返りたい。
あの頃の私をとっちめてやりたい。今にいたるまでの私が改善することになった。

バージョンは以下。

 "next": "^14.2.16",

データ取得(Data Fetch)をuseEffect内部で行う✖

これは代表的なBad Practiceだ。
Next.js App RouterはReact Server Components(以下、RSC)を基本としており、データ取得についてもRSCにて取得することを想定している。
https://nextjs.org/docs/app/getting-started/fetching-data

可能な限り、useEffectは減らそう。useEffectを使うのは最終手段だ。

RSCでのGET MethodのFetchであれば、多重化排除(Request Memoization)を行ってくれるので、メタデータでのData FetchとページのData Fetchの重複に怯える必要はない(もちろん確認は必要だが)。
https://nextjs.org/docs/app/building-your-application/caching#request-memoization

多重化排除(Request Memoization)はFetch Cacheをno-storeにしても効いてくれる。なんてありがたい。
ページレンダリングコストを削減するうえで、重要な意識となる。

Server ComponentからClient Componentへユーザには隠匿したい情報を渡す✖

これは、Next.js App Routerがどのようにページをレンダリングしているかに対して理解が必要となる。
Server Componentはサーバーサイドでレンダリングが完結するが、Client Componentはサーバーサイドでプリレンダリングされたのち、ブラウザ側(クライアントサイド)でレンダリングされる。つまり、通信が発生し、引数に渡した情報はネットワークに載ってしまう。
したがって、Server ComponentでData Fetchした情報を丸々Client Componentに渡すと、場合によっては情報が流出する。使う情報のみをClient Componentに渡すべきだ。手打ちの型宣言をしたくないという場合には、Omitを利用しよう。
https://typescriptbook.jp/reference/type-reuse/utility-types/omit

私が曖昧な部分であることがわかったので、イメージだけ記載します。
サブタイプ貫通は今後の課題とさせてください。

ESLintのreact/jsx-props-no-spreadingを有効にすべきですね。
https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-props-no-spreading.md
https://qiita.com/sabawo/items/0de5638236835ca652be
しかし、私もスプリット構文での引数渡しは利用するので、本来は型厳密にできてほしいが。

2025/02/09追記:
https://zenn.dev/kagaya_22/articles/1887a1b5f90a4a
上記で解決しました。

Client-side Router Cacheを考慮せずにページ遷移する✖

これは、情報更新が可能なページを作成するときに対面する問題だ。
ページ遷移時にRouter Cacheが残っており、古いページが表示されてしまうことになる。
Next.js 15ではキャッシュ保持時間を開発者側で操作することが可能だが、Next.js 14ではexperimentalである(筆者は設定すべきと考えているが)。
暫定対応としてrouter.push()後にrouter.refresh()をしよう。

https://nextjs.org/docs/app/building-your-application/caching#client-side-router-cache
https://zenn.dev/akfm/articles/next-app-router-client-cache

環境変数の優先順位を意識しないで設定する✖

Next.jsの環境変数には優先順位がある。上記順で優先される。

process.env
.env.$(NODE_ENV).local
.env.local (Not checked when NODE_ENV is test.)
.env.$(NODE_ENV)
.env

これを知らないと、ステージング環境に開発環境の環境変数がお邪魔することになる。恐ろしい。
env.localはgitignoreに入れよう。急いで。今すぐに。

https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#environment-variable-load-order

ドキュメントを読まないで、記事サイトを参考にする✖

必要なことはドキュメントか、GitHubのIssueに書いてある。それを読んだうえで、記事サイトや個人サイトを参考にしよう。Next.jsは機能が多い。まずはドキュメントで概略をつかもう。そして、私の言っていることを信じるな!(本当は実装されているコードを信じるべきだ)

https://nextjs.org/docs
https://github.com/vercel/next.js/issues

Reactの展望を追わない✖

Reactの機能として新たに実装されるものは、Next.jsで利用されるといって良い。Server Action,Server Componentの概念ももとはReact由来だ。本当に困ったときは、Reactのドキュメントを見ると良いことが書いてある。
https://ja.react.dev/reference/rsc/use-server#security
とか。

Reactのバージョンアップや思想を追うとNext.jsの向かう方向がなんとなくわかる。
useフックとSuspenseの組み合わせはとても面白い。

背景のないオレオレアーキテクチャを採用する✖

業務でのプロダクトなのだから、採用に至った背景、基準を設けるべきだ。
参画する人数、機能数、技量。保守性。考えることは大きい。
オレオレであることは仕方がないが、説明はできるようにしよう。
コロケーション配置にするか、しないか。
ディレクトリ設計は奥が深い。私も格闘中だ。

appディレクトリの構造変更を考えない✖

appディレクトリはNext.jsのファイルルーティング機能を担っている。
ここに構造変更が入ると、ルーティングへの影響を考慮しなくてはいけない。
なので奥手になりがちだが、可読性や集合を意識したい。
そういう場合はRoute Groupsを利用しよう。layout.tsxを継承させたくない場合にも有効だ。
https://nextjs.org/docs/app/building-your-application/routing/route-groups#convention

終わりに

これからNext.jsを学ぶ方々が同じ轍を踏まないことを願う。

Discussion