Візуалізуйте рядок HTML як реальний HTML в компоненті React


159

Ось, що я спробував і як це виходить не так.

Це працює:

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

Це не так:

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

Властивість опису - це лише звичайний рядок вмісту HTML. Однак він відображається як рядок, а не як HTML чомусь.

введіть тут опис зображення

Будь-які пропозиції?

Відповіді:


50

Перевірте, чи не вийшов текст, який ви намагаєтеся додати до вузла, таким чином:

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

Замість цього:

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

якщо уникнути, слід перетворити його з боку сервера.

Вузол - це текст, тому що він уникнути

Вузол - це текст, тому що він уникнути

Вузол - це вузол купола, тому що його не уникнути

Вузол - це вузол купола, тому що його не уникнути


3
Це було питання. Рядок з описом уникнув HTML. Я його не відмітив, і зараз він прекрасно працює.
Серхіо Тапія

4
Будь ласка, уникайте використання dangerouslySetInnerHTMLнатомість використання Fragmentвід react v16. Перевірте наступну відповідь від @ brad-adams
Kunal Parekh

2
Вдячний згадкою @KunalParekh, але вони різні речі. Моя відповідь справедлива лише в тому випадку, якщо html знаходиться у вашій програмі (це означає, що це фактично JSX). Щоб проаналізувати HTML із зовнішнього джерела до jsx, вам потрібно буде знайти інше рішення.
Бред Адамс

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це рядок, а не об'єкт. Що ви маєте на увазі під неправильною розміткою? Ви маєте на увазі незакриті теги? React повинен просто зробити це ні?
Серхіо Тапія

Чи можете ви вставити тут console.log (this.props.match.description);
Іланус

Один приклад:&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;
Серхіо Тапія

У цьому випадку потрібно або використовувати .innerHTML або декодувати HTMLEntities.
Іланус

Повернути кілька рядків або HTML-код з тегами: функція htmlDecode (введення) {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, якщо (e.childNodes [індекс] .outerHTML) {returnString + = e.childNodes [індекс] .outerHTML; }} return returnString; }
Кріс Адамс

58

Я використовую 'react-html-аналізатор'

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

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

Джерело на npmjs.com

Підвищення коментаря @ okram для більшої наочності:

з його опису github: Перетворює рядки HTML безпосередньо в компоненти React, уникаючи необхідності використання небезпечноSetInnerHTML з npmjs.com Утиліта для перетворення рядків HTML в компоненти React. Уникає використання небезпечноSetInnerHTML та перетворює стандартні елементи HTML, атрибути та вбудовані стилі в їх еквіваленти React.


11
Чи використовує ця бібліотека "небезпечноSetInnerHTML" у фоновому режимі?
Омар

1
з її опису github: Converts HTML strings directly into React components avoiding the need to use dangerouslySetInnerHTMLвід npmjs.comA 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 є те , що у вас є контроль над. Чи не для надання будь - сирцю HTML при умови через API, наприклад. До початку FragmentAPI мені завжди було болі, тому потрібні додаткові spanобгортання, які іноді псувалимуться з гнучкими макетами. Коли я натрапив на це питання, шукаючи можливе рішення, я подумав, що поділюсь, як я обійшов справи.
Бред Адамс

2
Дякую! Це було єдине рішення, яке працювало в моєму випадку. Також, відповідаючи на коментар mrkvon щодо цієї відповіді: Ця відповідь дійсно містить html, тобто Some text <strong>wrapped with strong</strong>містить html-тег strong.
Бініта Бхараті

@BinitaBharati Але це не рядок. Якщо ви отримуєте рядок з API, наприклад "<p> Це рядок </p>" (або просто зберігаєте рядок у змінній), коли ви кладете цю рядок у <Fragment>, результат все одно буде містити < p> тег.
Muchdecal

1
@BradAdams. Хороший трюк, хоча. Я бачу випадки, коли це стане в нагоді.
Muchdecal


5

небезпечноSetInnerHTML

небезпечноSetInnerHTML є заміною React для використання innerHTML у DOM браузера. Взагалі, встановлення HTML-коду є ризикованим, оскільки легко ненавмисно піддавати своїх користувачів атак міжсайтового сценарію (XSS). Отже, ви можете встановити HTML безпосередньо з React, але вам доведеться набрати небезпечноSetInnerHTML та передати об’єкт за допомогою ключа __html, щоб нагадати собі, що це небезпечно. Наприклад:

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

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

3

Я використовую 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; }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 . У мене була вимога показати декілька символів uncode 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. Я рекомендую не використовувати "небезпечноSetInnerHTML".

// 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}
);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.