reactjsで生のhtmlをレンダリングする


154

これは、reactjsで未加工のHTMLをレンダリングする唯一の方法ですか?

// http://facebook.github.io/react/docs/tutorial.html
// tutorial7.js
var converter = new Showdown.converter();
var Comment = React.createClass({
  render: function() {
    var rawMarkup = converter.makeHtml(this.props.children.toString());
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        <span dangerouslySetInnerHTML={{__html: rawMarkup}} />
      </div>
    );
  }
});

私はJSXで何かをマークアップするクールな方法があることを知っていますが、主に生のhtml(すべてのクラス、インラインスタイルなど)をレンダリングできることに興味があります。このような複雑なもの:

<!-- http://getbootstrap.com/components/#dropdowns-example -->
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
    Dropdown
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
  </ul>
</div>

これらすべてをJSXで書き直す必要はありません。

多分私はこれについてすべて間違っていると考えています。訂正してください。


1
それはほぼJSXです。多くのマークアップを未加工のHTMLとしてレンダリングすると、Reactのようなライブラリを使用する利点が失われます。Reactに要素を処理させるために、小さな変更( "class"-> "className"など)を行うことをお勧めします。
ロス・アレン

2
この特定の例では、誰かがあなたのためにすでに作業を行っいますが、問題はまだ一般的なケースを表しています。
ランディモリス

回答:


43

html-to-reactnpmモジュールを活用できます。

注:私はモジュールの作成者で、数時間前に公開しました。バグやユーザビリティの問題を報告してください。


24
内部的には、dangerouslySetInnerHTMLを使用していますか?
Yash Sharma

2
コードを確認しました。それはdangerouslySetInnerHTMLを使用していないようです。
Ajay Raghav

マイクはまだこのnpmモジュールを積極的に維持していますか?
ダニエル

ちょっとダニエル、私はしません、そして貢献者の一人がそれを引き継ぎ、7ヶ月前に最後のリリースを公開しました。参照してくださいgithub.com/aknuds1/html-to-react
マイクNiklesに

これは、dangerouslySetInnerHTMLを使用しません。
Tessaracter

185

HTMLをレンダリングするためのより安全な方法があります。これについては、以前の回答で説明しました。4つのオプションがあり、最後に使用しdangerouslySetInnerHTMLます。

HTMLをレンダリングする方法

  1. 最も簡単-Unicodeを使用し、ファイルをUTF-8として保存し、をUTF-8に設定しcharsetます。

    <div>{'First · Second'}</div>

  2. より安全 -Javascript文字列内のエンティティにUnicode番号を使用します。

    <div>{'First \u00b7 Second'}</div>

    または

    <div>{'First ' + String.fromCharCode(183) + ' Second'}</div>

  3. または、文字列とJSX要素を含む混合配列。

    <div>{['First ', <span>&middot;</span>, ' Second']}</div>

  4. 最後の手段 -を使用して生のHTMLを挿入しますdangerouslySetInnerHTML

    <div dangerouslySetInnerHTML={{__html: 'First &middot; Second'}} />


私に必要なのは3または4だけです
Nicolas S.Xu 2018

dangerouslySetInnerHTML__html以外にどのような属性を受け取るのか疑問に思う
Juan Solano

30
私はこれらのスレッドが大好きです...暗黙的に:「#4を使用できないようにできることは何でもしてください」。全員:「#4はうまくいきました!」
deepelement

1
@JuanSolanoなし、TypeScript環境のオートコンプリートエントリによると。
Andreas Linnert

同様の質問、stackoverflow.com / questions / 19266197 /…で、この回答はあまりうまくいきませんでした。多分それはこの質問により適しているかもしれません、あるいは多分人々は答えを読んでいません...:D
425nesp

27

私はこれを素早く汚い状況で使用しました:

// react render method:

render() {
    return (
      <div>
        { this.props.textOrHtml.indexOf('</') !== -1
            ? (
                <div dangerouslySetInnerHTML={{__html: this.props.textOrHtml.replace(/(<? *script)/gi, 'illegalscript')}} >
                </div>
              )
            : this.props.textOrHtml
          }

      </div>
      )
  }

7
これは安全ではありません-HTMLに含まれている場合はどうなります<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" onload="alert('test');">か?
yjwong 2018年

11
レンダリングされるHTMLを制御できれば安全です
John

18

私はこの純粋なコンポーネントを試しました:

const RawHTML = ({children, className = ""}) => 
<div className={className}
  dangerouslySetInnerHTML={{ __html: children.replace(/\n/g, '<br />')}} />

特徴

  • className小道具を取る(それをスタイルするのが簡単)
  • 置き換え\n<br />(あなたは多くの場合、それをやりたいです)
  • 次のようなコンポーネントを使用する場合は、コンテンツをとして配置します。
  • <RawHTML>{myHTML}</RawHTML>

コンポーネントをGithubの要旨に配置しました:RawHTML:HTMLをレンダリングするReactJSの純粋なコンポーネント


12
export class ModalBody extends Component{
    rawMarkup(){
        var rawMarkup = this.props.content
        return { __html: rawMarkup };
    }
    render(){
        return(
                <div className="modal-body">
                     <span dangerouslySetInnerHTML={this.rawMarkup()} />

                </div>
            )
    }
}

上記の作業では、htmlをモーダルボディに渡していました。
Jozcar 2017年

11

dangerouslySetInnerHTMLは、ブラウザのDOMでinnerHTMLを使用するためのReactの代替品です。一般に、ユーザーが誤ってクロスサイトスクリプティング(XSS)攻撃にさらされる可能性があるため、コードからHTMLを設定することは危険です。

を介してDOMに挿入する前に、生のHTML(たとえばDOMPurifyを使用)をサニタイズする方が安全dangerouslySetInnerHTMLです。

DOMPurify -HTML、MathML、およびSVG用のDOM専用の超高速、超耐性XSSサニタイザー。DOMPurifyは安全なデフォルトで動作しますが、多くの構成可能性とフックを提供します。

import React from 'react'
import createDOMPurify from 'dompurify'
import { JSDOM } from 'jsdom'

const window = (new JSDOM('')).window
const DOMPurify = createDOMPurify(window)

const rawHTML = `
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
    Dropdown
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
  </ul>
</div>
`

const YourComponent = () => (
  <div>
    { <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(rawHTML) }} /> }
  </div>
)

export default YourComponent

これはまさに私がこの回答で探していたものです。賛成票が増えるはずです
llamerr

6

パーサーと呼ばれるこのライブラリを使用しました。それは私が必要とするもののために働きました。

import React, { Component } from 'react';    
import Parser from 'html-react-parser';

class MyComponent extends Component {
  render() {
    <div>{Parser(this.state.message)}</div>
  }
};

3
21KB(8KB gzip圧縮)。ブラウザのコードではそれを正当化できませんでした。
Peter Bengtsson、

このライブラリは私のExpoアプリを壊します
ekkis

5

dangerouslySetInnerHTMLどうしても必要な場合以外は使用しないでください。ドキュメントによると、「これは主にDOM文字列操作ライブラリと連携するためのものです」。これを使用すると、ReactのDOM管理のメリットを放棄することになります。

あなたの場合、有効なJSX構文に変換するのはかなり簡単です。class属性をに変更するだけですclassName。または、上記のコメントで述べたように、Bootstrap要素をReactコンポーネントにカプセル化するReactBootstrapライブラリを使用できます。


8
ご回答有難うございます。innerHTMLを使用することによるセキュリティへの影響を理解し、それをJSXに変換できることを知っています。しかし、私は具体的に生のHTMLスニペットを使用するためのReactのサポートについて尋ねています。
vinhboy 2015年

「生のHTMLスニペットを使用するためのReactのサポート」とはどういう意味ですか?
Breno Ferreira

2

これは、以前に投稿されたRawHTML関数のやや控えめなバージョンです。次のことができます。

  • タグを構成する
  • 必要に応じて改行に置き換える<br />さん
  • RawHTMLが作成した要素に渡す追加の小道具を渡す
  • 空の文字列(RawHTML></RawHTML>)を指定します

ここにコンポーネントがあります:

const RawHTML = ({ children, tag = 'div', nl2br = true, ...rest }) =>
    React.createElement(tag, {
        dangerouslySetInnerHTML: {
            __html: nl2br
                ? children && children.replace(/\n/g, '<br />')
                : children,
        },
        ...rest,
    });
RawHTML.propTypes = {
    children: PropTypes.string,
    nl2br: PropTypes.bool,
    tag: PropTypes.string,
};

使用法:

<RawHTML>{'First &middot; Second'}</RawHTML>
<RawHTML tag="h2">{'First &middot; Second'}</RawHTML>
<RawHTML tag="h2" className="test">{'First &middot; Second'}</RawHTML>
<RawHTML>{'first line\nsecond line'}</RawHTML>
<RawHTML nl2br={false}>{'first line\nsecond line'}</RawHTML>
<RawHTML></RawHTML>

出力:

<div>First · Second</div>
<h2>First · Second</h2>
<h2 class="test">First · Second</h2>
<div>first line<br>second line</div>
<div>first line
second line</div>
<div></div>

それは壊れるでしょう:

<RawHTML><h1>First &middot; Second</h1></RawHTML>

0

divが許可されていない頭の中でonLoad属性を持つリンクを使用する必要があったため、これは私に大きな痛みを引き起こしました。現在の回避策は、元のスクリプトタグを閉じて、必要な操作を行ってから、スクリプトタグを開くことです(元のスクリプトタグによって閉じられます)。これが他に選択肢がない人を助けることを願っています:

<script dangerouslySetInnerHTML={{ __html: `</script>
   <link rel="preload" href="https://fonts.googleapis.com/css?family=Open+Sans" as="style" onLoad="this.onload=null;this.rel='stylesheet'" crossOrigin="anonymous"/>
<script>`,}}/>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.