Next.jsの_documment..tsxと_app.tsxについてメモ

## _app.tsxとは
`/page/_app.tsx`を作成することでAppコンポーネントをカスタマイズができる。
すべてのページコンポーネントの初期化に使われるコンポーネント。
すべてのページで共通な処理などを書くことができる。

## _documment.tsxとは
`/page/_documment.tsx`を作成することでDocumentコンポーネントをカスタマイズができる。
htmlタグやbodyタグの定義を行うコンポーネント
ページ共通のheadタグなどを定義する


_app.tsxの例
```_app.jsx
import { AppProps } from 'next/app'
import Head from 'next/head'

const App = ({ Component, pageProps }: AppProps) => (
  <>
    <Head>
      <title />
        <meta name='viewport' content='width=device-width, initial-scale=1' />
    </Head>
    <Component {...pageProps} />
  </>
)

export default App
```

_documents.tsxの例
```_documents.jsx
import NextDocument, { Html, Head, Main, NextScript } from 'next/document'

type Props = {}

class Document extends NextDocument<Props> {
  render() {
    return (
      <Html lang="ja-JP">
        <Head>
          <meta charSet="utf-8" />
          <meta name="format-detection" content="telephone=no" />
          <link rel="shortcut icon" href={'/favicon.ico'} />
          <link rel="apple-touch-icon" href={'/logo.png'} />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default Document
```
※NextDocumentクラスの継承が必要


_app.tsxと_documents.tsxは全ページ共通に設置しておきたい処理を記述できます。
アナリティクスタグなんかも設置していいと思います。

注意点として_documents.tsxには
`<title />`タイトルタグや
`<meta name='viewport' content='width=device-width, initial-scale=1' />`metaのviewportは設置すると怒られるみたいなので、
_app.tsxに記述しましょう。


### Contextで共通なグローバルな値を管理する
_app.tsxは全ページ共通になるので、グローバルな値を管理するのにも使えます。
カスタムhookにAppContextがあるていです。
```_app.jsx
import { AppProps } from 'next/app'
import Head from 'next/head'
import { AppContext } from '@hooks/useApp'
const App = ({ Component, pageProps }: AppProps) => (
  const value = '値'
  <>
    <Head>
      <title />
        <meta name='viewport' content='width=device-width, initial-scale=1' />
    </Head>
    <AppContext.Provider value={value}>
      <Component {...pageProps} />
    </AppContext.Provider>
  </>
)

export default App
```
こんな感じで_app.tsxにContextを設置しておけばグローバルな値として、
全てのページで共通の値を使えます。

### ページごとにmetaなどを変えたい場合

ページによってタイトルやmeta情報を変更したい場合があると思います。
まずはheadタグまとめたコンポーネントを作ってあげます。

```head.jsx
import * as React from 'react';
import Head from 'next/head';

export default ({ title, description, keyword, image, url }: Props) => {
  return (
    <Head>
      <title>{title}</title>
      <meta property="og:title" content={title} />
      <meta property="og:description" content={description} />
      <meta name="keywords" content={keyword} />
      <meta property="og:type" content="blog" />
      <meta property="og:url" content={url} />
      <meta property="og:image" content={image} />
      <meta property="og:site_name" content={title} />
      <meta name="twitter:card" content="summary" />
      <meta name="twitter:site" content="text.jp" />
      <meta name="twitter:url" content={image} />
      <meta name="twitter:title" content={title} />
      <meta name="twitter:description" content={description} />
      <meta name="twitter:image" content={image} />
    </Head>
  );
};
```

```test.jsx
import Head from 'next/head';

function testPage() {
  return (
    <>
      <Head 
          title={'タイトル'}
          description={'ディスクリプション'}
          keyword={'キーワード'}
          image={'/img.jpg'}
          url={'https://test.jp'}
       />
    </>
  );
}

export default testPage;
```
こうしてあげると各ページごとにタイトルやmetaを設定することができます。


_documment..tsxと_app.tsxについてと
ちょっとした派生的な実装をご紹介いたしました。
(実際に動かしたわけではないので、なにかあればご指摘いただけますと幸いです。。)