React 컴포넌트에서 HTML 문자열을 실제 HTML로 렌더링


159

여기 내가 시도한 것과 그것이 어떻게 잘못되었는지가 있습니다.

이것은 작동합니다 :

<div dangerouslySetInnerHTML={{ __html: "<h1>Hi there!</h1>" }} />

이것은하지 않습니다 :

<div dangerouslySetInnerHTML={{ __html: this.props.match.description }} />

description 속성은 일반적인 HTML 콘텐츠 문자열입니다. 그러나 어떤 이유로 HTML이 아닌 문자열로 렌더링됩니다.

여기에 이미지 설명을 입력하십시오

어떤 제안?

답변:


50

노드에 추가하려는 텍스트가 다음과 같이 이스케이프되지 않았는지 확인하십시오.

var prop = {
    match: {
        description: '&lt;h1&gt;Hi there!&lt;/h1&gt;'
    }
};

이 대신에 :

var prop = {
    match: {
        description: '<h1>Hi there!</h1>'
    }
};

이스케이프 된 경우 서버 측에서 변환해야합니다.

이스케이프 되었기 때문에 노드는 텍스트입니다.

이스케이프 되었기 때문에 노드는 텍스트입니다.

이스케이프되지 않았기 때문에 노드는 DOM 노드입니다.

이스케이프되지 않았기 때문에 노드는 DOM 노드입니다.


3
이것이 문제였습니다. 설명 문자열이 HTML에서 이스케이프되었습니다. 나는 그것을 이스케이프 처리하지 않고 이제는 잘 작동합니다.
Sergio Tapia

4
반응 v16에서 dangerouslySetInnerHTML대신 사용 하지 마십시오 Fragment. 체크 다음 대답 @ 브래드 - 아담스
쿠날 Parekh 씨

2
@KunalParekh의 언급을 감사하지만 다른 것입니다. 내 대답은 html이 앱 내에있는 경우에만 유효합니다 (실제로 JSX임을 의미). 외부 소스에서 jsx로 HTML을 구문 분석하려면 다른 솔루션을 찾아야합니다.
브래드 아담스

113

합니까는 this.props.match.description문자열 또는 객체인가? 문자열이면 HTML로 변환해야합니다. 예:

class App extends React.Component {

constructor() {
    super();
    this.state = {
      description: '<h1 style="color:red;">something</h1>'
    }
  }

  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.state.description }} />
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));

결과 : http://codepen.io/ilanus/pen/QKgoLA?editors=1011

그러나 description: <h1 style="color:red;">something</h1>따옴표 가 없으면 다음 ''을 얻을 수 있습니다.

Object {
$$typeof: [object Symbol] {},
  _owner: null,
  key: null,
  props: Object {
    children: "something",
    style: "color:red;"
  },
  ref: null,
  type: "h1"
}

문자열이고 HTML 마크 업이 표시되지 않는 경우 내가 볼 수있는 유일한 문제는 잘못된 마크 업입니다 ..

최신 정보

HTMLEntitles를 다루는 경우. 보내기 전에 해독해야합니다dangerouslySetInnerHTML 하므로 그것이 위험하다고 불렀습니다. :)

작업 예 :

class App extends React.Component {

  constructor() {
    super();
    this.state = {
      description: '&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;'
    }
  }

   htmlDecode(input){
    var e = document.createElement('div');
    e.innerHTML = input;
    return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
  }

  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.htmlDecode(this.state.description) }} />
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));

this.props.match.description문자열이 아니라 객체입니다. 잘못된 마크 업이란 무엇입니까? 닫히지 않은 태그를 의미합니까? 반응이 그냥 안되나요?
Sergio Tapia

여기에 붙여 넣을 수 있습니까 console.log (this.props.match.description);
Ilanus

예 :&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;
Sergio Tapia

이 경우 .innerHTML을 사용하거나 HTMLEntities를 디코딩해야합니다.
Ilanus

태그가있는 여러 줄 또는 HTML 코드를 반환합니다. function htmlDecode (input) {var e = document.createElement ( 'div'); e.innerHTML = 입력; var returnString = ''; for (index = 0; index <e.childNodes.length; index ++) {// 문자열의 경우 if (e.childNodes [index] .nodeValue) {returnString + = e.childNodes [index] .nodeValue; } // HTML의 경우 if (e.childNodes [index] .outerHTML) {returnString + = e.childNodes [index] .outerHTML; }} return returnString; }
Chris Adams

58

'react-html-parser'를 사용합니다.

yarn add react-html-parser
import ReactHtmlParser from 'react-html-parser'; 

<div> { ReactHtmlParser (html_string) } </div>

npmjs.com의 소스

더 많은 가시성을 위해 @okram의 의견을 높이십시오.

github 설명에서 : npmjs.com에서 risklySetInnerHTML을 사용하지 않아도 HTML 문자열을 React 구성 요소로 직접 변환 HTML 문자열을 React 구성 요소로 변환하는 유틸리티. dangerouslySetInnerHTML의 사용을 피하고 표준 HTML 요소, 속성 및 인라인 스타일을 React와 동등한 것으로 변환합니다.


11
이 라이브러리는 백그라운드에서 "dangerouslySetInnerHTML"을 사용합니까?
오마르

1
github 설명에서 : Converts HTML strings directly into React components avoiding the need to use dangerouslySetInnerHTMLnpmjs.com에서A utility for converting HTML strings into React components. Avoids the use of dangerouslySetInnerHTML and converts standard HTML elements, attributes and inline styles into their React equivalents.
okram

14

html을 포함하는 문자열이 어디에서 왔는지 (예 : 앱의 어딘가) 제어 할 수 있다면 새로운 기능을 활용할 수 있습니다 <Fragment> 다음과 같이 API를 .

import React, {Fragment} from 'react'

const stringsSomeWithHtml = {
  testOne: (
    <Fragment>
      Some text <strong>wrapped with strong</strong>
    </Fragment>
  ),
  testTwo: `This is just a plain string, but it'll print fine too`,
}

...

render() {
  return <div>{stringsSomeWithHtml[prop.key]}</div>
}

11
예제에 html을 포함하는 문자열이 없습니다. jsx 또는 일반 문자열입니다.
mrkvon

3
글쎄, 기술적으로는 @mrkvon의 말이 맞지만, 언급 한 바와 같이이 솔루션 은 "html"/ jsx가 제어 할 수있는 경우에만 유효합니다. 예를 들어 API를 통해 제공된 일부 원시 HTML 을 렌더링하는 것은 아닙니다 . FragmentAPI 이전에는 항상 span플렉스 레이아웃으로 엉망 이되는 추가 랩이 필요하다는 것이 항상 고통 스럽습니다. 나는 가능한 솔루션을 찾고이 질문에 발견하면 나는 어떻게 공유하고자 내가 일을 주위 얻었다.
Brad Adams

2
감사! 이것이 내 경우에 효과가 있었던 유일한 솔루션이었습니다. 또한이 답변에 대한 mrkvon의 의견에 답변 :이 답변에는 실제로 html이 포함되어 있습니다 (예 : Some text <strong>wrapped with strong</strong>html 태그 포함) strong.
Binita Bharati가

@BinitaBharati 그러나 그것은 문자열이 아닙니다. "<p> This is a String </ p>"과 같은 API에서 문자열을 얻는 경우 (또는 단순히 문자열을 변수에 저장) <Fragment>에이 문자열을 넣으면 출력에 여전히 < p> 태그.
Muchdecal

1
@BradAdams. 그래도 좋은 트릭. 편리한 인스턴스를 볼 수 있습니다.
Muchdecal

6

당신은 React의 dangerouslySetInnerHTML 메소드를 사용합니다.

<div dangerouslySetInnerHTML={{ __html: htmlString }} />

또는 다음과 같은 쉬운 방법으로 더 많은 것을 구현할 수 있습니다. React 앱에서 HTML 원시 렌더링


5

dangerouslySetInnerHTML

dangerouslySetInnerHTML은 브라우저 DOM에서 innerHTML을 사용하는 React의 대체품입니다. 일반적으로 코드에서 HTML을 설정하면 사용자가 실수로 XSS (Cross-Site Scripting) 공격에 노출되기 때문에 위험합니다. 따라서 React에서 직접 HTML을 설정할 수는 있지만, 위험하다는 것을 상기시키기 위해 dangerouslySetInnerHTML을 입력하고 __html 키로 객체를 전달해야합니다. 예를 들면 다음과 같습니다.

function createMarkup() {
  return {__html: 'First &middot; Second'};
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}

3

span을 사용하여 innerHTML을 함께 사용합니다.

import React, { useRef, useEffect, useState } from 'react';

export default function Sample() {
  const spanRef = useRef<HTMLSpanElement>(null);
  const [someHTML,] = useState("some <b>bold</b>");

  useEffect(() => {
    if (spanRef.current) {
      spanRef.current.innerHTML = someHTML;
    }
  }, [spanRef.current, someHTML]);

  return <div>
    my custom text follows<br />
    <span ref={spanRef} />
  </div>
}

나는이 고급 스러움이 없을 때 추가 라이브러리 또는 서버 측에 의존 할 필요가 없습니다. 당신에게 영감을 얻었지만 클래스 구성 요소에서 componentDidMount() { this.message.current.innerHTML = this.state.selectedMessage.body; }본문은 나에게 탈출 된 HTML입니다.
webhound

2

제 경우에는 react-render-html을 사용했습니다.

먼저 다음을 통해 패키지를 설치하십시오. npm i --save react-render-html

그때,

import renderHTML from 'react-render-html';

renderHTML("<a class='github' href='https://github.com'><b>GitHub</b></a>")

1

나는 npm build일할 수 없었다 react-html-parser. 그러나 필자의 경우 https://reactjs.org/docs/fragments.html 을 성공적으로 사용할 수있었습니다 . HTML 유니 코드 문자를 거의 표시하지 않아도되지만 JSX에 직접 포함해서는 안됩니다. JSX 내에서 구성 요소의 상태에서 선택해야했습니다. 구성 요소 코드 스 니펫은 다음과 같습니다.

constructor() 
{
this.state = {
      rankMap : {"5" : <Fragment>&#9733; &#9733; &#9733; &#9733; &#9733;</Fragment> , 
                 "4" : <Fragment>&#9733; &#9733; &#9733; &#9733; &#9734;</Fragment>, 
                 "3" : <Fragment>&#9733; &#9733; &#9733; &#9734; &#9734;</Fragment> , 
                 "2" : <Fragment>&#9733; &#9733; &#9734; &#9734; &#9734;</Fragment>, 
                 "1" : <Fragment>&#9733; &#9734; &#9734; &#9734; &#9734;</Fragment>}
                };
}

render() 
{
       return (<div class="card-footer">
                    <small class="text-muted">{ this.state.rankMap["5"] }</small>
               </div>);
}


-2

{this.props.match.description}에 대한 제어 권한이 있고 JSX를 사용중인 경우 "dangerouslySetInnerHTML"을 사용하지 않는 것이 좋습니다.

// In JSX, you can define a html object rather than a string to contain raw HTML
let description = <h1>Hi there!</h1>;

// Here is how you print
return (
    {description}
);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.