React入門 02: ライブラリMarkedでMarkdownの機能を加える

gumitech

gumi TECH

Posted on December 9, 2019

React入門 02: ライブラリMarkedでMarkdownの機能を加える

「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


Enter fullscreen mode Exit fullscreen mode

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>
  );
};


Enter fullscreen mode Exit fullscreen mode

テキストは子コンポーネント(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>
  );
};


Enter fullscreen mode Exit fullscreen mode

図001■タグがテキストとして表示される

02_003.png

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 };
};


Enter fullscreen mode Exit fullscreen mode

図002■MarkdownテキストがHTMLとして描かれる

02_004.png

書き改めたふたつのコンポーネントの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;


Enter fullscreen mode Exit fullscreen mode

コード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;


Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
gumitech
gumi TECH

Posted on December 9, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related