🚀

【Next.js和訳】Advanced Features/Custom `Document`

4 min read

この記事について

株式会社 UnReact はプロジェクトの一環としてNext.js ドキュメントの和訳を行っています。

この記事は、Advanced Features/Custom `Document`の記事を和訳したものです。

記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。

Custom Document

カスタム Document は通常、アプリケーションの <html><body> タグを拡張するために使用されます。Next.js ページは周囲のドキュメントのマークアップの定義を省略するため、これが必要です。

デフォルトの Document を上書きするには、./pages/_document.js というファイルを作成し、以下に示すように Document クラスを拡張します。

import Document, { Html, Head, Main, NextScript } from "next/document"
class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    return { ...initialProps }
  }
  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}
export default MyDocument

上記のコードは、Next.js によって追加されたデフォルトの Document です。getInitialProps または render 関数を変更する必要がない場合は、MyDocument から自由に削除してください。

ページを適切にレンダリングするためには、<Html><Head /><Main /> および <NextScript /> が必要です。

カスタム属性は、lang のように、props として許可されています。

<Html lang="en">

ここで使用されている <Head /> コンポーネントは、next/headのものとは異なります。ここで使用される <Head /> コンポーネントは、すべてのページに共通する <head> コードにのみ使用されるべきです。<title> タグなど、その他のケースでは、ページまたはコンポーネントでnext/headを使用することをお勧めします。

ctx オブジェクトはgetInitialPropsで受け取ったものと同じですが、1 つだけ追加されています。

  • renderPageFunction - 実際の React レンダリングロジックを(同期的に)実行するコールバックです。Aphrodite のrenderStaticのようなサーバーレンダリングのラッパーをサポートするために、この関数を装飾すると便利です。

警告

  • Document はサーバーでのみレンダリングされるため、onClick のようなイベントハンドラーは機能しません。
  • <Main /> の外側にある React コンポーネントはブラウザによって初期化されません。ここにアプリケーションロジックやカスタム CSS( styled-jsx など)を追加しないでください。すべてのページで共有コンポーネント(メニューやツールバーなど)が必要な場合は、代わりにAppコンポーネントを確認してください。
  • DocumentgetInitialProps 関数は、クライアントサイドの遷移中、またはページが静的に最適化されている場合には呼び出されません。
  • Document は現在、getStaticPropsまたはgetServerSidePropsのような Next.js のData Fetching methodsをサポートしていません。

Customizing renderPage

なお、renderPage をカスタマイズするのは、サーバーサイドレンダリングを適切に動作させるためにアプリケーションをラップする必要があるcss-in-jsライブラリを使用する場合のみです。

さらにカスタマイズするために、引数としてオプションオブジェクトを取ります。

import Document from "next/document"
class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const originalRenderPage = ctx.renderPage
    ctx.renderPage = () =>
      originalRenderPage({
        // リアクトツリー全体を包み込むのに便利です。
        enhanceApp: (App) => App,
        // ページ単位で包み込むのに便利です。
        enhanceComponent: (Component) => Component,
      })
    // 親の `getInitialProps` を実行すると、カスタムの `renderPage` が含まれるようになります。
    const initialProps = await Document.getInitialProps(ctx)
    return initialProps
  }
}
export default MyDocument

TypeScript

組み込みの DocumentContext タイプを使用して、ファイル名を ./pages/_document.tsx のように変更できます。

import Document, { DocumentContext } from "next/document"
class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const initialProps = await Document.getInitialProps(ctx)
    return initialProps
  }
}
export default MyDocument

Discussion

ログインするとコメントできます