【Next.js入門⑦】withRouterで動的なページを作成する

f:id:nekorokkekun:20190909164734p:plain:w1000
こちらの連載記事では、Next.jsの入門チュートリアルを紹介しながら、最終的にポートフォリオファイルの完成を目指します。

筆者もNext.jsビギナーなので、同じくNext.jsに触れるのが初めてだという方を対象に書き進めていきます。

目標の確認

今回は以下のように動的なページの作成をしていきましょう。

分かりにくいですが、押したタイトルリストによって遷移先の文章が変わっています。

これをwithRouterというNext.jsの機能を用いて実現させましょう。

非同期通信で読み込むJSONデータを設定する

まずは読み込むJSONデータをJSONPlaceholderというサイトから拝借します。

非同期通信のためにaxiosを使用するのでパッケージをインストールしましょう。

$ npm install axios

また以下のようにportfolios.jsを編集してください。
pages/portfolios.js

||<import React from 'react';
import BaseLayout from '../components/layouts/BaseLayout';
import Link from 'next/link';
import axios from 'axios';

class Portfolios extends React.Component{

    static async getInitialProps() {
  // JSONデータの格納先を用意
        let posts = [];

        try {
  // JSONデータを取得し、responseに格納
            const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
  // postに格納
            posts = response.data;
        } catch(err) {
            console.error(err);
        }
  // JSONデータの10行目までをreturn
        return {posts: posts.splice(0,10)};
    }

    renderPosts(posts) {
  // .mapでpostアレイを展開(foreach的な)
        return posts.map((post, index) => {
            return (
                <li key={index}> // ユニークキーの設定
  // 動的なリンクを生成。GETのパラメータにtitleクエリが入る
                    <Link href={`/portfolio?title=${post.title}`}>
                        <a style={{'fontSize': '20px'}}>{post.title}</a>
                    </Link>
                </li>
            )
        })
    }
    render() {
        const { posts } = this.props;
        return (
            <BaseLayout>
                <h1>This is Portfolio page.</h1>
                <ul>
     // 受け取ったpropsをrenderPostsで展開
                    { this.renderPosts(posts) }
                </ul>
            </BaseLayout>
        )
    }
}

export default Portfolios;
>||


次にportfoliosの各JSONデータを受け取るファイルを作成しましょう。
pages/portfolio.js
>|javascript|
import React from 'react';
import BaseLayout from '../components/layouts/BaseLayout';
import { withRouter } from 'next/router';

class Portfolio extends React.Component{
    render() {
        return (
            <BaseLayout>
                <h1>This is a Portfolio page.</h1>
                <h1>{this.props.router.query.title}</h1>
            </BaseLayout>
        )
    }
}

export default withRouter(Portfolio);

これで想定通りの動的なページができました。

ただ、pages/portfolios.jsからportfolio.jsに移る際のクエリがあまりにも長すぎるため以下のよう書き方に変えましょう。
pages/portfolios.js

                <li>
                    <Link as={`/portfolio/${post.id}`} href={`/portfolio?title=${post.title}`}>
                        <a style={{'fontSize': '20px'}}>{post.title}</a>
                    </Link>
                </li>

as=とすることによって、クエリパラメータがidへと置きかわります。こちらの方がスマートに見えますね。