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을 원시 HTML로 렌더링하면 React와 같은 라이브러리를 사용하면 이점이 사라집니다. React가 요소를 처리 할 수 ​​있도록 작은 변경 (예 : "class"-> "className")을 수행하는 것이 좋습니다.
Ross Allen

2
이 특정 예에서 누군가가 이미 귀하를 위해 작업을 수행 했지만 질문은 여전히 ​​일반적인 경우를 나타냅니다.
랜디 모리스

답변:


43

html-to-reactnpm 모듈을 활용할 수 있습니다.

참고 : 나는 모듈의 저자이며 몇 시간 전에 방금 게시했습니다. 버그 또는 사용성 문제를보고하십시오.


24
내부적으로 dangerouslySetInnerHTML을 사용합니까?
Yash Sharma

2
방금 코드를 확인했습니다. 위험하게 SetInnerHTML을 사용하지 않는 것 같습니다.
Ajay Raghav

Mike 아직도이 npm 모듈을 적극적으로 유지하고 있습니까?
Daniel

이봐 다니엘, 내가 안하고 공헌자 중 한 명이 그것을 인수하고 7 개월 전에 마지막 릴리스를 발표했습니다. github.com/aknuds1/html-to-react
Mike Nikles

이것은 위험하게 SetInnerHTML을 사용하지 않습니다.
Tessaracter

185

이제 HTML을 렌더링하는 더 안전한 방법이 있습니다. 나는 이전의 대답이 덮여 여기 . 마지막 사용 방법은 4 가지 dangerouslySetInnerHTML입니다.

HTML 렌더링 방법

  1. 가장 쉬움 -유니 코드를 사용하고 파일을 UTF-8로 저장 한 후 UTF-8로 설정하십시오 charset.

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

  2. 더 안전-Javascript 문자열 내 엔터티에 유니 코드 번호를 사용하십시오.

    <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

dangerouslySetInnerHTML__html 외에 다른 속성이 무엇인지 궁금해
Juan Solano

30
나는이 스레드를 좋아한다 ... 암묵적으로 : "# 4를 사용할 수없는 것은 무엇이든한다" 여러분 : "# 4는 훌륭하게 작동했습니다!"
deepelement 2016 년

1
TypeScript 환경의 자동 완성 항목에 따라 @JuanSolano 없음.
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

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의 Gist에 구성 요소를 배치했습니다. 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

11

dangerouslySetInnerHTML 은 브라우저 DOM에서 innerHTML을 대체하는 React의 대체품입니다. 일반적으로 코드에서 HTML을 설정하면 사용자가 실수로 XSS (Cross-Site Scripting) 공격에 노출되기 때문에 위험합니다.

를 통해 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

이것이 내가이 대답에서 정확히 찾은 것입니다. 더 많은
투표를

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 gzipped). 브라우저 코드에 대해서는 그것을 정당화 할 수 없었습니다.
Peter Bengtsson

이 라이브러리는 내 엑스포 앱을
깨뜨 렸습니다

5

dangerouslySetInnerHTML꼭 필요한 경우가 아니면 사용하지 마십시오. 문서에 따르면 "이것은 주로 DOM 문자열 조작 라이브러리와 협력하기위한 것 입니다. " 사용하면 React의 DOM 관리의 이점을 포기하게됩니다.

귀하의 경우 유효한 JSX 구문으로 변환하는 것은 매우 간단합니다. class속성을로 변경하십시오 className. 또는 위의 주석에서 언급 한 것처럼 Bootstrap 요소를 React 구성 요소로 캡슐화 하는 ReactBootstrap 라이브러리를 사용할 수 있습니다 .


8
답변 주셔서 감사합니다. innerHTML 사용의 보안 영향을 이해하고 JSX로 변환 할 수 있음을 알고 있습니다. 그러나 나는 원시 HTML 스 니펫 사용에 대한 React의 지원에 대해 구체적으로 묻고 있습니다.
vinhboy

"원시 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.