Next.jsのインストールとルーティングの基礎

## Next.jsとは？
Next.jsとは、Reactのユニバーサルフレームワークです。Nowでお馴染みのzeit.coが開発していて、以下のような特徴があります。

- SSR（サーバーサイドレンダリング）
- 高速なページロードのための自動コード分割
- ページベースのクライアントサイドルーティング
- webpackベースの開発環境で、Hot Module Replacement（HMR）をサポート
- Express等のHTTPサーバーと一緒に実装可能
- Babelやwebpackの設定をカスタマイズ可能

このエントリーでは、[公式のチュートリアル](https://nextjs.org/learn/basics/getting-started)をもとに、Next.jsのインストールと、ルーティングの基礎をまとめてみました。

## インストール

```sh
$ mkdir hello-next
$ cd hello-next
$ npm init -y
$ npm install --save react react-dom next
$ mkdir pages
```

package.jsonには以下のnpm scriptsを記述します。

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

`npm run dev`で`http://localhost:3000`にローカルサーバーが立ち上がります。現在は404になっているので、簡単なページを追加してみましょう。

```jsx
// pages/index.js
const Index = () => (
  <div>
    <p>Hello Next.js</p>
  </div>
)

export default Index
```

ブラウザ上に`Hello Next.js`が表示されたかと思います。

## ディレクトリの命名規則とルーティング
Next.jsでは、`pages`ディレクトリがルーティングの対象になります。それ以外のコンポーネントを配置するディレクトリ名にルールはなく、たとえばコンポーネント用のディレクトリは、`components`でも、`comps`でもなんでもOKです。

### シンプルなルーティング

```jsx
// pages/index.js

// This is the Link API
import Link from 'next/link'

const Index = () => (
  <div>
    <Link href="/about">
      <a>About Page</a>
    </Link>
    <p>Hello Next.js</p>
  </div>
)

export default Index
```

```jsx
// pages/about.js
const About = () => {

  // ヒストリーバックでもOK
  const historyBack = () => {
    history.back()
  }
  
  return (
    <div>
      <button onClick={historyBack}>History Back</button>
      <p>This is About Page</p>
    </div>
  )
}

export default About
```

### 共通コンポーネントを使用

```jsx
// components/Header.js
import Link from 'next/link'

// スタイル
const linkStyle = {
  marginRight: 15
}

// ヘッダー用コンポーネント
const Header = () => (
  <div>
    <Link href="/">
      <a style={linkStyle}>Home</a>
    </Link>
    <Link href="/about">
      <a style={linkStyle}>About</a>
    </Link>
  </div>
)

export default Header
```

```jsx
// pages/index.js
import Header from '../components/Header'

const Index = () => (
  <div>
    <Header />
    <p>Hello Next.js</p>
  </div>
)

export default Index
```

```jsx
// pages/about.js
import Header from '../components/Header'

const About = () => (
  <div>
    <Header />
    <p>This is About Page</p>
  </div>
)

export default About
```

### Layoutを継承

ベースとなるレイアウトコンポーネントを作成し、継承できます。ページコンポーネントの受け取り方はいくつかありますので、チュートリアルで紹介されているほうほうをご紹介します。

#### childrenでページコンポーネントを受け取る
```jsx
// components/MyLayout.js
import Header from './Header'

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

const Layout = props => (
  <div style={layoutStyle}>
    <Header />
    {
      // 引数でpages/*.jsのJSXを受け取る
      props.children
    }
  </div>
)

export default Layout
```

```jsx
// components/Header.js
import Link from 'next/link'

// スタイル
const linkStyle = {
  marginRight: 15
}

// ヘッダー用コンポーネント
const Header = () => (
  <div>
    <Link href="/">
      <a style={linkStyle}>Home</a>
    </Link>
    <Link href="/about">
      <a style={linkStyle}>About</a>
    </Link>
  </div>
)

export default Header
```

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

const Index = () => (

  // カスタムエレメントの小要素が渡される
  <Layout>
    <p>Hello Next.js</p>
  </Layout>
)

export default Index
```

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

const About = () => (

  // カスタムエレメントの小要素が渡される
  <Layout>
    <p>This is About Page</p>
  </Layout>
)

export default About
```

#### ページコンポーネントをカスタムエレメントで受け取る
```jsx
// components/MyLayout.js
import Header from './Header'

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

const withLayout = Page => {
  return () => (
    <div style={layoutStyle}>
      <Header />
      <Page />
    </div>
  )
}

export default withLayout
```

```jsx
// pages/index.js
import withLayout from '../components/MyLayout'

const Page = () => <p>Hello Next.js</p>

export default withLayout(Page)
```

```jsx

// pages/about.js
import withLayout from '../components/MyLayout'

const Page = () => <p>This is the about page</p>

export default withLayout(Page)
```

#### contentでページコンポーネントを受け取る

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

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

const Layout = props => (
  <div style={layoutStyle}>
    <Header />
    {
      // 引数でpages/*.jsのJSXを受け取る
      props.content
    }
  </div>
)

export default Layout
```

```jsx

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

const indexPageContent = <p>Hello Next.js</p>

export default function Index() {

  // カスタムエレメントのpropsでJSXを渡す
  return <Layout content={indexPageContent} />
}
```

```jsx

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

const aboutPageContent = <p>This is the about page</p>

export default function About() {

  // カスタムエレメントのpropsでJSXを渡す
  return <Layout content={aboutPageContent} />
}
```

ちなみに、チュートリアルの`Using Shared Components`までの内容です。

続きはまた。