[Next.js] uuidから動的にページを生成したい

14727 ワード

やりたいこと

新規投稿ボタンを押した際に、
/articles/[uuid]/edit
というURLを作成したい

やりかた

next/link または next/router をつかう

  • next/linkの場合
import Link from 'next/link'

function Posts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/articles/${encodeURIComponent(uuid)}`}/edit>
            <a>{post.title}</a>
          </Link>
        </li>
      ))}
    </ul>
  )
}

export default Posts
  • next/routerの場合
import { useRouter } from 'next/router'

export default function Page() {
  const router = useRouter()

  return (
    <button type="button" onClick={() => router.push('/articles/[uuid]/edit')}>
      Click me
    </button>
  )
}

Hooks can only be called inside of the body of a function component

下記のようにボタンを押した際に createNewArticle を実行するようにしたところ、
「Hooks can only be called inside of the body of a function component」という
エラーが出力された

import { NextRouter, Router, useRouter } from 'next/router';
import { uuid } from 'uuidv4';

const createNewArticle = () => {
  const router = useRouter();
  router.push({
    pathname: '/articles/[uuid]/edit',
    query: { uuid: uuid() },
  });
};

const Hogehoge = () => {
  return (
    <>
    ...省略
      <button
        type="button"
        onClick={() => createNewNote()}
      >
        投稿
      </button>
    </>
  );
};
Unhandled Runtime Error

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

原因

useRoutercreateNewArticle の中で定義されてしまっているため
コンポーネントを読み込んだ時点でどのフックが使われるかを明示するために、
useRouter がメソッド内の一番外側で定義されるように修正する必要があった

import { NextRouter, Router, useRouter } from 'next/router';
import { uuid } from 'uuidv4';

const createNewArticle = (router: NextRouter) => {
  router.push({
    pathname: '/articles/[uuid]/edit',
    query: { uuid: uuid() },
  });
};

const Hogehoge = () => {
  const router = useRouter();
  return (
    <>
    ...省略
      <button
        type="button"
        onClick={() => createNewNote(router)}
      >
        投稿
      </button>
    </>
  );
};

参考

Next.jsにおけるURLの管理・制御の方法(next/linkとnext/router)
React Hooksのルールをよく理解しないとハマるエラー対処法
next/link
next/router