バイト先でNext.jsを使っていて、v6から入った_appと、以前からある_documentの違いがよくわかっていなかったので調べてまとめました。基本的にはこれの一部を和訳しているので、よくわからなかったらそちらを参照してください。
_document
これが定義されている場合には、<html>要素をレンダリングするトップレベルのドキュメントをオーバーライドすることができます。しかし、これにはいくつかの重大な制限が存在します。例えば、Reactは<html>や<body>をクライアント側で直接レンダリングすることはできません。そのため、_documentの呼び出しはレンダリング前に限定されます。
_app
_appはそのほかのユースケースに対しても使うことができます。
| Prerender phase | Runtime lifecycle | Data fetching | |
|---|---|---|---|
_document |
YES | NO | NO |
_app |
YES | YES | YES |
例1)ページトランジション
この例では、ページごとに独立してアクセスし、プリレンダリングをし、遅延ロードをしていますが、クライアント側に移行するとなめらかなアニメーションを行います。
例2)良質なApolloやReduxとの統合
Nextではすでに、ApolloやReduxのような状態管理フレームワークと統合した例が数多くありましたが、_appを使えばそれらを含めるのが容易になります。
例3)良質なエラーハンドリング
ReactはcomponentDidCatchというコンポーネントメソッドを用意しています。このメソッドを使用すると、クライアント側のネストされたコンポーネントの例外をキャッチして処理できます。
これらの予期しない例外は、トップレベルでキャッチして均等に処理しておきたいというケースが多くあります。_appは、そのcomponentDidCatchロジックを定義するのに適しています。
感想
以前までは各ページをHOCに食わせるなどして共通の事前処理を行っていたので、その必要がなくなったということで、HOC地獄から少し開放されたような気がしています。