LoginSignup
0
0

Next.jsでブログ記事に目次を実装する(Tocbot使用)

Posted at

はじめに

ブログサイトを作る過程で学んだことを、備忘録目的で投稿しています。
自身は駆け出しエンジニアであり、React自体がほぼ初学者のため、誤った認識・理解をしている可能性があります。
万が一参考にする場合は、上記の点を考慮した上でご一読ください。
また、スタイリングについては割愛しています。

この記事は、過去に投稿したNext.js × microCMSでブログサイト作成した際に学んだことを書き留めるのプロジェクトを元に説明しています。

目的

記事詳細ページにて、Qiitaのような目次を実装する。

作業環境

Windows10 Pro x64
Node.js: 20.14.0
npm: 10.3.0
Next.js: 14.2.3(App Router使用)

手順

実装にあたりTocbotというライブラリを使用します。

まずはインストールします。

npm install --save tocbot

Tocbotを呼び出すファイルと、それを使用するTocBoxコンポーネントを作成します。
useEffectを使用するためサーバーレンダリングではなく、クライアントレンダリングにする必要があります。("use client"
下記だと、.tocの子要素に<nav className="toc"></nav>が追加されます。

/src/libs/tocbot.js
"use client";

import { useEffect } from "react";
import tocbot from "tocbot";

export const Toc = () => {
  useEffect(() => {
    tocbot.init({
      tocSelector: ".toc", // 目次を追加する class 名
      contentSelector: ".target-toc", // 目次を取得するコンテンツの class 名
      headingSelector: "h2, h3, h4", // 目次として取得する見出しタグ
      headingsOffset: 100, // 見出しのオフセット
      scrollSmoothOffset: -40, //スムーススクロールのオフセット
    });

    // 不要となったtocbotインスタンスを削除
    return () => tocbot.destroy();
  }, []);

  return <nav className="toc" />;
};

/src/components/TocBox/index.jsx
import styles from "./index.module.scss";
import { Toc } from "@/libs/tocbot";

export const TocBox = () => {
  return (
    <>
      <p className={styles.title}>目次</p>
      <Toc />
    </>
  );
};

作成したTocBoxコンポーネントを詳細ページで呼び出します。

/src/app/articles/[slug]/page.jsx
import Image from "next/image";
import parse from "html-react-parser";
import styles from "./page.module.scss";
import { getArticlesDetail } from "@/libs/microcms";
import { TocBox } from "@/components/TocBox"; // 追加

export default async function Page({ params }) {
  const article = await getArticlesDetail(params.slug);
  return (
    <main className={styles.main}>
      <div className={styles.container}>
        <div className={styles.article}>
          <p className={styles.thumbnail}>
            <Image
              src={article.thumbnail.url}
              alt={article.title}
              height={article.thumbnail.height}
              width={article.thumbnail.width}
              priority
            />
          </p>
          <h1 className={styles.title}>{article.title}</h1>
          <p className={styles.category}>{article.category.name}</p>
          <div className={`${styles.body} target-toc`}>
            {parse(article.body)}
          </div>
        </div>

        {/* 追加 */}
        <div className={styles.toc}>
          <TocBox />
        </div>

      </div>
    </main>
  );
}

記事を投稿し、確認してみます。
image.png

目次が設置できました。
要素を検証すると、見出しレベル毎にクラス名が割り振られていたり(例:node-name--H2)、アクティブの見出しにもクラス名が付与されていたりなど(例:is-active-link)、スタイル調整がしやすくなっています。
また、目次内のリンクをクリックすると、該当箇所までスムーススクロールしてくれます。
image.png

さいごに

理想は目次もSSGに対応させたかったのですが、今の自分の力量では実現できず断念しました。
Tocbotはオプションも充実しているのでとても使いやすかったです、ぜひ使用してみてください、

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0