简体   繁体   中英

React dangerouslySetInnerHTML Inside Fragment

I have a use-case where I need to format some text in React and also render HTML.

Here is an example of what I'm currently trying to achieve:

import React, {Fragment} from "react";
import {renderToString} from "react-dom/server";

function FormatText(props) {
  const lines = props.children.split('\n');

  return lines.map((line, index) => (
    <Fragment key={index}>
      {line}{index !== lines.length - 1 && <br/>}
    </Fragment>
  ));
}

const content = {
  first: 'This is some text\nwith new\n\nline characters - 1',
  second: 'This is some text\nwith new\n\nline <strong>characters - <sup>2</sup></strong>',
};

function App() {
  return (
    <ol>
      <li>
        <FormatText>{content.first}</FormatText>
      </li>
      <li dangerouslySetInnerHTML={{
        __html: renderToString(<FormatText>{content.second}</FormatText>)
      }}/>
    </ol>
  )
}

As you can see, I have some content which contains \\n characters and HTML. Calling the renderToString function converts the HTML into encoded characters, which means the HTML is not rendered properly.

Is there a way to render HTML inside a react fragment.

Ideally I wanted to do the following (but it doesn't):

function FormatText(props) {
  const lines = props.children.split('\n');

  return lines.map((line, index) => (
    <Fragment key={index} dangerouslySetInnerHTML={{__html: renderToString(
        <Fragment>
          {line}{index !== lines.length - 1 && <br/>}
        </Fragment>
      )}}>
    </Fragment>
  ));
}
  • <Fragment> doesn't adds any node to DOM and so you can't do dangerouslySetInnerHTML on it . It is basically a functionality provided by React to avoid addition of extra node to DOM when you needed to return more than one from return in render. So, if something doesn't exists on real DOM, you can't do anything on it .
  • renderToString is generally used on node server. When doing server side rendering, you want to send the html from server to client. So, better avoid renderToString also.

The issue is that, html doesn't recognises \\n for new line etc. It needs html tags. The approach to use FormatText is fine or you can simply convert the \\n to br and then use dangerouslySetInnerHTML inside the <li> tag.

 const content = { first: 'This is some text\\nwith new\\n\\nline characters - 1', second: 'This is some text\\nwith new\\n\\nline <strong>characters - <sup>2</sup></strong>', }; function App() { return ( <ol> <li dangerouslySetInnerHTML={{ __html: content.first.replace(/\\n/g, "<br/>") }}/> <li dangerouslySetInnerHTML={{ __html: content.second.replace(/\\n/g, "<br/>") }}/> </ol> ) } ReactDOM.render(<App/>, document.getElementById("root"))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script> <div id="root"></div>

Hope it helps. Revert for any doubts.

Hi I guess it is not possible, only way hot to pass formated html into DOm is via dom element DIV.

Maybe this link could help you or point to https://reactjs.org/docs/dom-elements.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM