React入門 02: ライブラリMarkedでMarkdownの機能を加える
gumi TECH
Posted on December 9, 2019
「React入門 01: コンポーネントを組み立てる」(以下「React入門 01」)では、簡単なコンポーネントを組み合わせて、シンプルなSPAのページをつくりました。今回は、Reactで差し込む要素のテキストを、Markdownで書いてみます。MarkdownのテキストをHTMLの記述に変えるために使うのは、JavaScriptライブラリMarkedです。また、Reactで生のHTMLコードを差し込む場合の特別な仕組みについてもご説明します。
Markdown記法とMarkedのインストール
「Markdown」は、テキストの書式を定める簡易な記法です。HTMLコードよりも簡単な書き方で、文字や段落の表記が整えられます。JavaScriptライブラリMarkedは、npmでReactアプリケーションのディレクトリにつぎのようにインストールします。
npm install marked --save
marked()
関数でMarkdownをHTMLの記述に変える
「React入門 01」で書いたJavaScriptコードに手を加えてゆきましょう。まず、src/components/CommentList.js
のテキストにつぎのようにMarkdown記法を加えます。*
(アスタリスク)と_
(アンダースコア)は同じ働きです。それを確かめるために、あえて両方用いました。記号ひとつで文字を挟めば強調・斜体(<em>
)、ふたつなら強い重要性・太字(<strong>
)になります。
const CommentList = () => {
return (
<div className="CommentList">
<Comment author="ヘンリー・キッシンジャー">
チャンスは__貯金__できない。
</Comment>
<Comment author="マーク・トウェイン">
禁煙なんてたやすい。私は*何千回*もやった。
</Comment>
</div>
);
};
テキストは子コンポーネント(src/components/Comment.js
)が受け取りますので、MarkdownテキストをHTMLの記述に変換するコードは、項目のコンポーネント(Comment
)に書き加えます。Markedライブラリからimport
するのは関数marked()
です。引数に渡したMarkdownのテキストをHTMLの記述にして返します。なお、引数は文字列でなければならないので、children
で得た子要素はtoString()
メソッドで文字列にしておきましょう。
ところが、JavaScriptコードをつぎのように書き替えて、marked()関数の戻り値をそのまま差し込むと、タグがテキストとして示されてしまいます(図001)。
import marked from 'marked';
const Comment = (props) => {
return (
<div className="Comment">
{marked(props.children.toString())}
</div>
);
};
図001■タグがテキストとして表示される
dangerouslySetInnerHTML
によりHTMLのコードを差し込む
生のHTMLコードが差し込めてしまうと、「クロスサイトスクリプティング」(XSS)による攻撃を受けるかもしれません(「クロスサイトスクリプティング対策 ホンキのキホン」参照)。そのため、ReactはHTMLのタグは、そのままでは加えられないようにしたのです。テキストをHTMLとして差し込むためには、dangerouslySetInnerHTML
プロパティを用いなければなりません(「ReactのdangerouslySetInnerHTML使ってみた」参照)。与えるのはオブジェクトで、プロパティ__html
にHTMLコードを値として定めます。
もっとも、dangerouslySetInnerHTML
プロパティにオブジェクトを直に与えるのは安全といえません。別に定めたメソッド(rawMarkup()
)を呼び出し、その本体でHTMLコードをつくって返すのがよいでしょう。そこで、コンポーネント(Comment
)はさらにつぎのように書き替えます。プロパティに与えるメソッドの呼び出しは、波かっこ{}
でくくってください。こうすれば、コンポーネントの要素にはメソッドから返されたコードが、HTMLとして描かれるはずです(図002)。
const Comment = (props) => {
return (
<div className="Comment">
{/* {marked(props.children.toString())} */}
<span dangerouslySetInnerHTML={rawMarkup(props.children.toString())} />
</div>
);
};
const rawMarkup = (markup) => {
const rawMarkup = marked(markup);
return { __html: rawMarkup };
};
図002■MarkdownテキストがHTMLとして描かれる
書き改めたふたつのコンポーネントのJavaScriptコードは、それぞれ以下のコード001と002にまとめました。
コード001■src/components/CommentList.js
import React from 'react';
import Comment from './Comment';
const CommentList = () => {
return (
<div className="CommentList">
<Comment author="ヘンリー・キッシンジャー">
チャンスは__貯金__できない。
</Comment>
<Comment author="マーク・トウェイン">
禁煙なんてたやすい。私は*何千回*もやった。
</Comment>
</div>
);
};
export default CommentList;
コード002■src/components/Comment.js
import React from 'react';
import marked from 'marked';
const Comment = (props) => {
return (
<div className="Comment">
<h2 className="CommentAuthor">
{props.author}
</h2>
<span dangerouslySetInnerHTML={rawMarkup(props.children.toString())} />
</div>
);
};
const rawMarkup = (markup) => {
const rawMarkup = marked(markup);
return { __html: rawMarkup };
};
export default Comment;
Posted on December 9, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.