react-markdownに目次をつける


##はじめに
react-markdownの目次の作り方を紹介します。
(もっといい方法あるかもです。。)

[ソースコード](https://github.com/tokio-k/react-markdown-toc/tree/basic)

スタイリング0です
目次を押すと、該当の箇所に移動するだけのものを作ります。

##完成品

```index.js
import ReactMarkdown from "react-markdown";

const body = `
## タイトル1
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
## タイトル2
1. こんにちは。
2. こんにちは。
3. こんにちは。
1. こんにちは。
2. こんにちは。
3. こんにちは。
1. こんにちは。
2. こんにちは。
3. こんにちは。
## タイトル3
#### こんばんは
#### こんばんは　
#### こんばんは
#### こんばんは　
#### こんばんは　
#### こんばんは`

export default function Home() {
  const H2 = ({ node, ...props }) => {
    return (
        <h2 id={node.position?.start.line.toString()}>{props.children}</h2>
    );
  }

  const ankerLink = ({ node, ...props }) => {
    return (
        <a href={"#"+node.position?.start.line.toString()}>{props.children}</a>
    );
  }

  return (
    <div>

      {/* 目次 */}
      <ReactMarkdown
      allowedElements={["h2"]}
      components={{
          h2: ankerLink,
        }}>
          {body}
      </ReactMarkdown>

      {/* 本文 */}
      <ReactMarkdown
        components={{
          h2: H2,
        }}
      >
          {body}
      </ReactMarkdown>

    </div>
  )
}

```

[手順](#手順)では↑を順番に書いていくだけです。

##手順

###ライブラリのインストール

```
yarn add react-markdown
```

###マークダウンで書いたものを表示させる

```index.js
import ReactMarkdown from "react-markdown";

const body = `
## タイトル1
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
## タイトル2
1. こんにちは。
2. こんにちは。
3. こんにちは。
1. こんにちは。
2. こんにちは。
3. こんにちは。
1. こんにちは。
2. こんにちは。
3. こんにちは。
## タイトル3
#### こんばんは
#### こんばんは　
#### こんばんは
#### こんばんは　
#### こんばんは　
#### こんばんは`

export default function Home() {
  return (
    <div>
      <ReactMarkdown>
          {body}
        </ReactMarkdown>
    </div>
  )
}

```

bodyがマークダウンで書いた内容ですね
ReactMarkdownのchildrenにbodyを渡します。

こうやって書くこともできます

```ㅤ.js
<ReactMarkdown
  children={body}
/>
```

これでマークダウンで書かれたものをhtmlとして表示することができます。

###見出しにidを与える

```index.js

export default function Home() {
  const H2 = ({ node, ...props }) => {
    return (
        <h2 id={node.position?.start.line.toString()}>{props.children}</h2>
    );
  }
  return (
    <div>
      <ReactMarkdown
        components={{
          h2: H2,
        }}
      >
          {body}
        </ReactMarkdown>
    </div>
  )
}

```

componentsオプションを使うことで、要素を編集できます。
マークダウンのh2を自分で作ったh2にしています。
左に要素の指定、右に自分で作ったものを指定します。
今回はh2だけですが、h2とh3など複数指定できます。

nodeやporpsにどんな値が入っているかはconsole.logなどで確認してみてください。

###見出しだけを表示させる

```index.js

<ReactMarkdown allowedElements={["h2"]}>
    {body}
</ReactMarkdown>

```

これでh2のみが表示されます。

```index.js
<ReactMarkdown allowedElements={["h2"]}>
  {body}
</ReactMarkdown>

<ReactMarkdown
   components={{
     h2: H2,
   }}
>
  {body}
</ReactMarkdown>
```

目次ようと本文用で2つ作ります。

###見出しから飛べるようにする

```index.js
const ankerLink = ({ node, ...props }) => {
    return (
        <a href={"#"+node.position?.start.line.toString()}>{props.children}</a>
    );
}
```

```index.js
<ReactMarkdown
  allowedElements={["h2"]}
  components={{
     h2: ankerLink,
  }}>
  {body}
</ReactMarkdown>
```
見出しだけを表示している方のh2を編集します。
[見出しにidを与える](#見出しにidを与える)と同じようにh2を編集します

同じマークダウンを使っているので、idが同じになります。

これで目次をクリックすることで、見出しに飛ぶことができるようになりました。

あとは、自由にスタイリングしていってください。


## おまけ

このままだと、headerなどがある時に被ってしまいます。
H2に、「paddidng-top: 20px；」、「margin-top: -20px;」などを持たせることでいい感じに表示できます。

[Tailwind使って少しだけスタイリングしました](https://qiita.com/toki_k/items/10291c161800bda5e055)

## 参考文献

https://github.com/remarkjs/react-markdown