react-markdownを使ってみた

# はじめに
今回は、`react-markdown`というライブラリを使ってみた記事になります。

## react-markdownとは

> This package is a React component that can be given a string of markdown that it’ll safely render to React elements. You can pass plugins to change how markdown is transformed and pass components that will be used instead of normal HTML elements.
>
> このパッケージは、React要素に安全にレンダリングするマークダウンの文字列を渡すことができるReactコンポーネントです。マークダウンがどのように変換されるかを変更するプラグインを渡したり、通常のHTML要素の代わりに使用されるコンポーネントを渡したりすることができます。

https://github.com/remarkjs/react-markdown?tab=readme-ov-file#what-is-this

また、このような記述がありました。

> このパッケージは、初心者が React でマークダウンを安全に使用できるようにすることに重点を置いています

高機能なものではなく、あくまで初心者向けの手っ取り早く簡単にマークダウンを処理するためのライブラリであることがわかります。

### 使用バージョン
- react: ^18.3.1
- react-markdown: ^9.0.1
- remark-gfm: ^4.0.0

### 使ってみる
#### インストール
```zsh
npm install react-markdown
npm install remark-gfm
```

`remark-gfm`は、`react-markdown`で使用できるプラグインです。
いくつかの構文サポートを追加できます。

#### コード
```tsx
import "./index.css";
import { useState } from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";

function App() {
  const [markdown, setMarkdown] = useState<string>("");
  return (
    <div>
      <h1>react-markdown</h1>
      <h2>Markdown 入力</h2>
      <textarea
        placeholder="マークダウンを入力してください"
        value={markdown}
        onChange={(e) => setMarkdown(e.target.value)}
      />

      <h2>プレビュー</h2>
      <ReactMarkdown remarkPlugins={[remarkGfm]}>{markdown}</ReactMarkdown>
    </div>
  );
}

export default App;
```

<details><summary>css</summary>

CSSはchatGPTに出力してもらいました。
```css
body {
  font-family: "Hiragino Sans", "Hiragino Kaku Gothic ProN", "メイリオ",
    sans-serif;
  line-height: 1.6;
  padding: 20px;
  background-color: #f5f5f5;
}

/* 見出しのスタイル */
h1 {
  color: #333;
  text-align: center;
  margin-bottom: 20px;
}

h2 {
  color: #555;
  margin-top: 30px;
  margin-bottom: 10px;
}

/* テキストエリアのスタイル */
textarea {
  width: 100%;
  min-height: 150px;
  resize: vertical;
  margin-bottom: 20px;
  font-size: 16px;
  border: 1px solid #ccc;
  border-radius: 5px;
  background-color: #fff;
  box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
}

/* プレビュー領域のスタイル */
.ReactMarkdown {
  padding: 20px;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 5px;
  box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
  overflow: auto;
}
```
</details>

かなりシンプルに書けました。

## 画面
作成した画面は以下のようなものです。

![スクリーンショット 2024-12-23 20.53.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/de4bfb8d-b0b7-64b7-ff68-79b99d2a037d.png)

では、実際にマークダウン形式でテキストを入力してみます。

````md
# h1
## h2
### h3
#### h4
##### h5
###### h6

普通のテキスト

- リスト1
- リスト2
  - サブリスト1

1. 番号付きリスト1
2. 番号付きリスト2
3. 番号付きリスト3

**太字**
*斜体*
~~取り消し線~~

`インラインコード`

```
const codeBlock = "codeBlock";
```

```javascript
const greet = (name) => {
  return `Hello, ${name}!`;
};
```

[Link](/test)

> 引用1

---

- [ ] 未完了のタスク
- [x] 完了したタスク

| 見出し1 | 見出し2 |
|---------|---------|
| 内容1   | 内容2   |
| 内容3   | 内容4   |

Markdown:  
  軽量なマークアップ言語  
React:  
  JavaScriptライブラリ

<span style="color: red;">赤い文字</span>
 
[^1]: 注釈です。

<details>
  <summary>クリックして詳細を見る</summary>
  詳細な説明がここに入ります。
</details>

````
そして以下が表示されたものになります。

![スクリーンショット 2024-12-23 22.19.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/8a0514b3-804f-73dd-417f-cf5ab701e22f.png)
![スクリーンショット 2024-12-23 22.20.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/f4d9c87e-cfee-db14-1c6e-da7ae3bea39e.png)

最低限の記法には対応していそうです！

インラインコード・コードブロックは背景色などが変わっていないためわかりづらいですが、普通のテキストとは書体が異なるので正常に認識されていそうです。

2枚目下部の記法、spanを用いたテキストスタイルの変更や、Definition List、アコーディオン（折りたたみ）は対応していないようです。spanやアコーディオンはマークダウンの範囲外なので当たり前と言えば当たり前なのですが...

## おわりに

今回は`react-markdown`を使ってみた記事でした！

今回使用したプラグインは`remarkGfm`のみでしたが、他にも色々あるようなのでそちらもまた機会があれば試してみたいと思います。

最後までお読みいただきありがとうございました！