React - как передать HTML-теги в реквизит?

Я хочу иметь возможность передавать текст с тегами HTML, например:

<MyComponent text="This is <strong>not</strong> working." />

но внутри MyComponent метод рендеринга, когда я распечатываю this.props.text, он буквально печатает все:

This is <strong>not</strong> working.

есть ли способ сделать React parse HTML и выгрузить его правильно?

14 ответов


вы можете использовать смешанные массивы со строками и элементами JSX (см. docs здесь):

<MyComponent text={["This is ", <strong>not</strong>,  "working."]} />

здесь есть скрипка, которая показывает, что она работает:http://jsfiddle.net/7s7dee6L/

также, в крайнем случае, у вас всегда есть возможность вставки raw HTML но будьте осторожны, потому что это может открыть вас для атаки межсайтовых сценариев (XSS), если вы не дезинфицируете значения свойств.


на самом деле, есть несколько способов, чтобы пойти с этим.

вы хотите использовать JSX внутри вашего реквизита

вы можете просто использовать {}, чтобы заставить JSX анализировать параметр. Единственное ограничение такое же, как и для каждого элемента JSX: он должен возвращать только один корневой элемент.

myProp={<div><SomeComponent>Some String</div>}

лучший читаемый способ сделать это-создать функцию renderMyProp, которая вернет компоненты JSX (так же, как стандартная функция рендеринга), а затем просто вызовет myProp={ этот.renderMyProp ()}

вы хотите передать только HTML в виде строки

по умолчанию JSX не позволяет отображать необработанный HTML из строковых значений. Тем не менее, есть способ заставить его сделать это:

myProp="<div>This is some html</div>"

тогда в вашем компоненте вы можете использовать его так:

<div dangerouslySetInnerHTML=myProp={{ __html: this.renderMyProp() }}></div>

остерегайтесь, что это решение "может" открываться при атаках межсайтовых сценариев. Также остерегайтесь, что вы можете отображать только простой HTML, без тега JSX или компонента или другой фантазии вещи.

путь массива

в react вы можете передать массив элементов JSX. Это значит:

myProp={["This is html", <span>Some other</span>, "and again some other"]}

Я бы не рекомендовал этот метод, потому что:

  • он создаст предупреждение (отсутствующие ключи)
  • это не читается
  • это не совсем путь JSX, это больше Хак, чем предполагаемый дизайн.

дети так

добавление его для полноты, но в react, вы также можно получить всех детей, которые находятся "внутри" вашего компонента.

Итак, если я возьму следующий код:

<SomeComponent>
    <div>Some content</div>
    <div>Some content</div>
</SomeComponent>

тогда два divs будут доступны как это.реквизит.дети в SomeComponent и могут быть отображены со стандартным синтаксисом {}.

это решение идеально подходит, когда у вас есть только один HTML-контент для передачи вашему компоненту (представьте компонент Popin, который принимает только содержимое Popin как дети).

однако, если у вас есть несколько содержание, вы не можете использовать детей (или вам нужно, по крайней мере, объединить его с другим решением здесь)


можно использовать dangerouslySetInnerHTML

просто отправьте html как обычную строку

<MyComponent text="This is <strong>not</strong> working." />

и визуализировать в коде JSX следующим образом:

<h2 className="header-title-right wow fadeInRight"
    dangerouslySetInnerHTML={{__html: props.text}} />

просто будьте осторожны, если вы рендеринга данных, введенных пользователем. Вы можете стать жертвой атаки XSS

вот документация: https://facebook.github.io/react/tips/dangerously-set-inner-html.html


для меня это сработало, передав HTML-тег в props children

<MyComponent>This is <strong>not</strong> working.</MyComponent>


var MyComponent = React.createClass({

   render: function() {
    return (
      <div>this.props.children</div>
    );
   },

<MyComponent text={<span>This is <strong>not</strong> working.</span>} />

и затем в вашем компоненте вы можете сделать проверку prop следующим образом:

import React from 'react';
export default class MyComponent extends React.Component {
  static get propTypes() {
    return {
      text: React.PropTypes.object, // if you always want react components
      text: React.PropTypes.any, // if you want both text or react components
    }
  }
}

убедитесь, что вы выбрали только один тип опоры.


в приложении react на стороне клиента есть несколько способов рендеринга prop в виде строки с некоторым html. Один безопаснее другого...

1-Определите опору как jsx (мое предпочтение)

const someProps = {
  greeting: {<div>Hello<a href="/${name_profile}">${name_profile}</a></div>}
}


const GreetingComopnent = props => (
  <p>{props.someProps.greeting}</p>
)

• единственное требование здесь заключается в том, что любой файл, генерирующий эту опору, должен включать React как зависимость (в случае, если вы генерируете JSX опоры в вспомогательном файле и т. д.).

2-опасно установить innerHtml

const someProps = {
  greeting: '<React.Fragment>Hello<a href="/${name_profile}">${name_profile}</a></React.Fragment>'
}

const GreetingComponent = props => {
  const innerHtml = { __html: props.someProps.greeting }
  return <p dangerouslySetInnerHtml={innerHtml}></p>
}

• Второй подход не рекомендуется. Представьте себе поле ввода, входное значение которого отображается как опора в этом компоненте. Пользователь может ввести тег скрипта во входных данных, и компонент, отображающий эти входные данные, выполнит этот потенциально вредоносный код. Таким образом, этот подход может привести к появлению уязвимостей межсайтовых сценариев. Для получения дополнительной информации обратитесь к официальным документам React


вы можете сделать это двумя способами, о которых я знаю.

1- <MyComponent text={<p>This is <strong>not</strong> working.</p>} />

и после этого

class MyComponent extends React.Component {
   render () {
     return (<div>{this.props.text}</div>)
   }
}

или второй подход сделать это так

2- <MyComponent><p>This is <strong>not</strong> working.</p><MyComponent/>

и после этого

class MyComponent extends React.Component {
   render () {
     return (<div>{this.props.children}</div>)
   }
}

из React v16.02 можно использовать фрагмент.

<MyComponent text={<Fragment>This is an <strong>HTML</strong> string.</Fragment>} />

Подробнее: https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html


вы также можете использовать функцию компонента для передачи jsx через реквизит. например:

 var MyComponent = React.createClass({

   render: function() {
    return (
      <OtherComponent
        body={this.body}
      />
    );
   },

   body() {
     return(
       <p>This is <strong>now</strong> working.<p>
     );
   }

});

var OtherComponent = React.createClass({

  propTypes: {
    body: React.PropTypes.func
  },

  render: function() {
     return (
        <section>
          {this.props.body()}
        </section>
     );
  },

});

в моем проекте мне пришлось передать динамический фрагмент html из переменной и отобразить его внутри компонента. Поэтому я сделал следующее.

defaultSelection : {
    innerHtml: {__html: '<strong>some text</strong>'}
}

defaultSelection объект передается компоненту из

<HtmlSnippet innerHtml={defaultSelection.innerHtml} />

HtmlSnippet компонент

var HtmlSnippet = React.createClass({
  render: function() {
    return (
      <span dangerouslySetInnerHTML={this.props.innerHtml}></span>
    );
  }
});

пример Plunkr

react doc для dangerouslySetInnerHTML


Да, вы можете это сделать, используя массив mix со строками и элементами JSX. ссылка

<MyComponent text={["This is ", <strong>not</strong>,  "working."]} />

есть ли причина, по которой никто не предложил react-html-parser? Кажется, это хороший способ работать с импортированным HTML без необходимости делать это опасно

https://www.npmjs.com/package/react-html-parser


@matagus ответ подходит для меня, надеюсь, ниже фрагмент поможет тем, кто хочет использовать переменную внутри.

const myVar = 'not';
<MyComponent text={["This is ", <strong>{`${myVar}`}</strong>,  "working."]} />

добавили html в componentDidMount с помощью jQuery append. Это должно решить проблему.

 var MyComponent = React.createClass({
    render: function() {

        return (
           <div>

           </div>
        );
    },
    componentDidMount() {
        $(ReactDOM.findDOMNode(this)).append(this.props.text);
    }
});