Next.jsの機能

Next.jsを触るに当たり、必要そうな情報をまとめました。
（一部、[公式ドキュメント](https://nextjs.org/docs)の雰囲気和訳です）
メモ程度のものなので、ざっくりです。

学習しながら、随時更新していきます。

間違い等あれば、ご指摘いただけると幸いです。

## 静的なファイル

静的なファイルは `static/` に配置します。

## `<head>` の設定

```jsx
import Head from 'next/head'

function IndexPage() {
  return (
    <div>
      <Head>
        <title>My page title</title>
        <meta name="viewport" content="initial-scale=1.0, width=device-width" />
      </Head>
      <p>Hello world!</p>
    </div>
  )
}

export default IndexPage
```

## getInitialProps

ページがロードされたときにデータを取得します。`pages/` ディレクトリでのみ使用でき、子コンポーネントでは使用できません。

初期ページロード時はサーバーサイドで実行され、 `Link` またはルーティングAPIを使用して別ルートに移動する際はクライアント上で実行されます。

### 受け取るコンテキストオブジェクト
- pathname - URLのパスセクション
- query - オブジェクトとして解析されたURLのクエリ文字列セクション
- asPath- Stringブラウザに表示される実際のパス（クエリを含む）の
- req - HTTP要求オブジェクト（サーバのみ）
- res - HTTP応答オブジェクト（サーバのみ）
- err - レンダリング中にエラーが発生した場合はエラーオブジェクト

## ルーティング

`pages/` 間を移動できます。

```jsx
import Link from 'next/link'

function Home() {
  return (
    <div>
      Click{' '}
      <Link href="/about">
        <a>here</a>
      </Link>{' '}
      to read more
    </div>
  )
}

export default Home
```

`<Link>` コンポーネントには2つの主な属性があります。

- href：`pages/` ディレクトリ内のパスとクエリ文字列
- as：ブラウザのURLバーに表示されるパス。

```html
<Link href="/post?slug=something" as="/post/something">
```

プロダクションのみの機能ですが、 `prefetch` 属性をつけるとページをプリフェッチします。

## 動的インポート

Next.jsは、JavaScript用のTC39動的インポート提案をサポートしています。これにより、JavaScriptモジュール（React Componentsを含む）を動的にインポートしてそれらを使用できます。

```jsx
import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() => import('../components/hello'))

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponent />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home
```

## `<App>` のカスタマイズ

`./pages/_app.js` を作成することによって、 `<App>` を上書きできます。

```jsx
import React from 'react'
import App, { Container } from 'next/app'

class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    let pageProps = {}

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx)
    }

    return { pageProps }
  }

  render() {
    const { Component, pageProps } = this.props

    return (
      <Container>
        <Component {...pageProps} />
      </Container>
    )
  }
}

export default MyApp
```

## `<Document>` のカスタマイズ

`./pages/_document.js` を作成することにより、ベースのマークアップを上書きできます。

```jsx
// _document is only rendered on the server side and not on the client side
// Event handlers like onClick can't be added to this file

// ./pages/_document.js
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>
          <style>{`body { margin: 0 } /* custom! */`}</style>
        </Head>
        <body className="custom_class">
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument
```

## エラーページのカスタマイズ

`pages/_error.js` を作成することにより、 `404` または `500` エラーの上書きができます。

```jsx
import React from 'react'

class Error extends React.Component {
  static getInitialProps({ res, err }) {
    const statusCode = res ? res.statusCode : err ? err.statusCode : null
    return { statusCode }
  }

  render() {
    return (
      <p>
        {this.props.statusCode
          ? `An error ${this.props.statusCode} occurred on server`
          : 'An error occurred on client'}
      </p>
    )
  }
}

export default Error
```

## next.config.jsによるNext.jsのカスタマイズ

`next.config.js` により、webpackの設定等をカスタマイズできます。

```js
// next.config.js
module.exports = {
  /* config options here */
};
```

もしくは、

```js
module.exports = (phase, { defaultConfig }) => {
  return {
    /* config options here */
  };
};
```

その他、詳しくは公式ドキュメントを参照。
https://nextjs.org/docs