3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[React]どこからか受け取ったHTMLの文字列を、HTML要素として画面に表示しつつ、特定ワードでハイライトしたい

Last updated at Posted at 2020-01-21

背景

開発中のシステムで、データベースにHTMLが入っているカラムがあり、それをAPIで取ってきて、Reactで表示するという構成の画面があります。
その画面にはHTML内の文字列を検索できる機能があり、「検索ワードをハイライトして表示できないか?」という相談を受けたので、実装しました。

(Google検索だと、ハイライトではなく太字になっていますが、やりたいことはこんな感じです)
Screen Shot 2020-01-22 at 4.59.49.png

ただ文字列をハイライトするのはかんたんですが、HTMLとしてレンダリングしつつというところで少し悩んだので記事にしました。

できたもの

だいたいこのような感じです。

Jan-22-2020 05-30-59.gif

HTMLに対して、スペース区切りで文字を入力したら、入力された文字とマッチする箇所をハイライトします。

codesandboxに上げました。

Edit react-innerHTML-highlight-words

ポイント

文字をハイライトさせるのには、react-highlight-wordsというパッケージが便利だったので使っています。
処理の流れは、

  1. (HTMLのstring)HTMLをstateから受け取る
  2. (React elementでstringをラップ)ハイライトしてくれるコンポーネントに突っ込む
  3. (HTMLのstring)react-dom/serverでサーバで一旦レンダリングする
  4. (HTMLのstring)正規表現でHTMLタグをアンエスケープする
  5. (React Element)dangerouslySetInnerHTMLというHTMLのstringをReactでHTML要素として表示できるプロパティに入れる

という感じです。
もしかしたらもっといいやり方があるかもですね。

HTMLタグのアンエスケープはこれでできます。

    const unescapeHtml = string => {
      const patterns = {
        "&lt;": "<",
        "&gt;": ">",
        "&amp;": "&",
        "&quot;": '"',
        "&#x27;": "'",
        "&#x60;": "`"
      };

      const escapedString = string.replace(
        /&(lt|gt|amp|quot|#x27|#x60);/g,
        match => patterns[match]
      );

      return escapedString;
    };

注意

HTML内部のリンクとマッチするワードが入力されたら、HTMLがこわれます。
必要ならエスケープすることになります。
また、もととなるデータが、ユーザーが自由に入れることができるものである場合は、XSS対策などセキュリティ対策が必要です。

3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?