What's "Next.js" ?

よく使い方を忘れるので、必要な時にサッと読み返せるように超完結にまとめておきます。

>勉強中の関連記事まとめ
>[自分用の勉強記事をまとめた目次　~擬似知識体系~](https://qiita.com/oekaki-hoho-ron/items/3194f560efc461ec03b0)

# Next.jsとは

Reactでサーバーサイドレンダリングを可能とするJavascriptフレームワーク

[Vue.js](https://jp.vuejs.org/index.html)でサーバーサイドレンダリングを可能とする[Nuxt.js](https://ja.nuxtjs.org/)の親戚

- デフォルトでサーバーサイドレンダリング
- 高速ページローディングのため自動でコードスプリッティング
- シンプルなクライアントサイドでページごとにルーティングが作られる
- HMRをサポートしたWebpackベースの開発環境
- Expressや、どのNode.jsのHTTPサーバでも実行可能
- BabelやWebpackでの独自カスタマイズが容易


> [Next.js公式サイト](https://nextjs.org/)
> [GitHub - README](https://github.com/zeit/next.js)

# 環境構築

公式サイトのチュートリアルに従って環境構築していく

>参考文献
>[公式サイトチュートリアル](https://nextjs.org/learn/basics/getting-started)
>[Next.jsチュートリアル翻訳](https://qiita.com/tetsutaroendo/items/31300a5e475688a2f4ec)

### セットアップ

```.zsh
mkdir test
cd test
npm init -y
npm install --save next react react-dom
mkdir pages
```

`package.json`をエディタで開いく

```.zsh
vi package.json
```

npmスクリプト`"scripts"`の値を`,`の有無に注意しながら編集（ここの内容についてまだイマイチ理解してない）

```package.json
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
```

devサーバーを起動する。

```.zsh
npm run dev
```

この段階では[http://localhost:3000/](http://localhost:3000/)に接続しても、Next.jsのデフォルトの404ページが表示される

>エラーページをカスタマイズするなら`pages/_error.js`を作成
>[Custom error handling](https://github.com/zeit/next.js/#custom-error-handling)

# indexページを作成

トップページの`index.js`を作成

Next.js の Link API では`pages/`ディレクトリ配下のファイルのツリー構造にそって自動でルーティング（indexからの関係性）設定がされる



```.zsh
mkdir pages
vi pages/index.js
```

ページ内容を記述

`pages/`ディレクトリ配下のファイルでReactコンポーネントをdefault exportさせることで、ページのコンポーネントとして認識

```index.js
const Index = () => (
  <div>
    <p>ようこそ</p>
  </div>
);

export default Index;
```

```
↓なんだこれ？
export default () => <div>ようこそ</div>
```

devサーバーを起動

```.zsh
npm run dev
```

[http://localhost:3000/about](http://localhost:3000/about)に接続して動作確認

indexページとaboutページをそれぞれ作成したがまだ相互にリンクされていない

# aboutページを作成

トップページ意外に固定ページとして`pages/`にaboutページを作成

```.zsh
vi pages/about.js
```

ページの内容を記述

```about.js
export default function About() {
  return (
    <div>
      <p>このサイトについて</p>
    </div>
  );
}
```

[http://localhost:3000/about](http://localhost:3000/about)に接続するとaboutページが表示される

しかし、indexとaboutをそれぞれ作成したが、まだ相互にリンクされていない

# 固定ページへのリンク

indexとaboutの2つのページをリンクさせるために`next/link`を使用する

Next.jsのLink APIを使用

 Linkページをプリフェッチしているため、この遷移はページを更新せずにすなわちクライアントサイドで処理され、サーバーサイドにはリクエストされずにナビゲーションされる

ブラウザの戻るボタンを押すと、クライアントサイドのみで戻ります。これはつまり、next/linkがlocation.historyをすべてハンドリングしてくれているわけです。

`pages/index.js`にコードを追記

```index.js
// This is the Link API
import Link from 'next/link';

const Index = () => (
  <div>
    <Link href="/about">
      <a>このページについて</a>
    </Link>
    <p>ようこそ</p>
  </div>
);

export default Index;
```

抜粋すると、`<link>`タグでレンダリングした要素に`next/link`をインポートしている

```index.js
<a href="/about">このページについて</a>

//　これをnext/Linkで使うと下のようになる

<Link href="/about">
  <a>このページについて</a>
</Link>
```

[http://localhost:3000/](http://localhost:3000/)にアクセスするとaboutページへのリンクが表示される

`<Link>`タグにtitle属性を追加

```index.js
<Link href="/about" title="About Page">
  <a>About Page</a>
</Link>
```

# 中略

#レイアウトコンポーネント

複数ページで共通するレイアウトを記述する`components/MyLayout.js`を作成

ここでHeaderやFooterのレイアウトを設定する

```components/MyLayout.js
import Header from './Header'

const layoutStyle = {
  margin: 20,
  padding: 20,
  border: '1px solid #DDD'
}

const Layout = (props) => (
  <div style={layoutStyle}>
    <Header />
    {props.children}
  </div>
)

export default Layout
```

`MyLayout.js`を各ページでインポート

```pages/index.js
import Layout from '../components/MyLayout.js'

export default () => (
    <Layout>
       <p>Hello Next.js</p>
    </Layout>
)
```

```pages/about.js
import Layout from '../components/MyLayout.js'

export default () => (
    <Layout>
       <p>This is the about page</p>
    </Layout>
)
```














#制作中サイトのコード

自分のサイトをNext.js仕様にしている最中のコード。

```Header.js
import Link from 'next/link';    // next.jsのlink APIを読み込み

const linkStyle = {    // <Link>タグのcss
  marginRight: 15
};

const Header = () => (    // Headerテンプレートの中身を定数Headerに代入
  <div>
    <Link href="/">    // トップページへのリンク
      <a style={linkStyle}>Home</a>
    </Link>
    <Link href="/profile">    // プロフィールページへのリンク
      <a style={linkStyle}>Profile</a>
    </Link>
  </div>
);

export default Header;    // Headerという名前で呼び出せるように書き出す
```

```MyLayout.js
import Header from '../components/Header';     // Headerテンプレートを読み込み
 
const layoutStyle = {    // レイアウトのcssを定数layoutStyleに代入
  margin: 20, 
  padding: 20, 
  border: '1px solid #DDD' 
}; 
 
const Layout = props => ( 
  <div style={layoutStyle}>     // <div>のcssとしてlayoutStyleを適用
    <Header />    // Headerテンプレートを適用
    {props.children}    // pages/の固定ページの要素を読み込み
  </div> 
); 
 
export default Layout;    // Layoutという名前で呼び出せるように書き出す
```

```index.js
import Layout from '../components/MyLayouts';    // MyLayoutテンプレートを読み込み

export default function Index() {
  return (
    <Layout>    // Layoutテンプレートを適用
      <p>サイト名</p>    /// {props.children}で読み込む内容を記述
    </Layout>
  );
}
```

```profile.js
import Layout from '../components/MyLayouts';

export default function Profile() {
  return (
    <Layout>
      <p>Profile</p>
    </Layout>
  );
} 
```

###レイアウトコンポーネントの使い方は2種類

1つ目は、公式チュートリアルにある「Method 1 - Layout as a Higher Order Component（高次コンポーネントとしてのレイアウト）」について。`MyLayout.js`をインポートしてレイアウト情報の入った`定数withLayout`を取得しておき、固定ページのコンテンツが入った`定数Page`の値を、`export default`の`関数withLayout`の引数として渡して`<Page />`の位置に吐き出すという処理。

2つ目は、公式チュートリアルにある「Method 2 - Page content as a prop（小道具としてのページコンテンツ）」について。`MyLayout.js`をインポートしてレイアウト情報の入った`定数Layout`を取得しておき、固定ページの`<Layout>`の中身の要素の入った`定数IndexPageContent`の値を、`export default`の関数で`{props.children}`の位置に吐き出すという処理。

どっちが使いやすいか、どういう使い分けをするのかは、分からん。

>参考文献
>[Using Shared Components（共有コンポーネントの使用） - Next.js公式チュートリアル](https://nextjs.org/learn/basics/using-shared-components/rendering-children-components)