How do I convert a string to jsx?

Viewed 89607

How would I take a string, and convert it to jsx? For example, if I bring in a string from a textarea, how could I convert it to a React element;

var jsxString = document.getElementById('textarea').value;

What is the process I would use to convert this on the client? Is it possible?

11 Answers

Personally, I love to do it just like in the previous answer which recommends the usage of dangerouslySetInnerHTML property in JSX.

Just for an alternative, nowadays there is a library called react-html-parser. You can check it and install from NPM registry at this URL: https://www.npmjs.com/package/react-html-parser. Today's weekly download statistic for that package is 23,696. Looks a quite popular library to use. Even it looks more convenient to use, my self, still need more read and further consideration before really using it.

Code snippet copied from the NPM page:

import React from 'react';
import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser';

class HtmlComponent extends React.Component {
  render() {
    const html = '<div>Example HTML string</div>';
    return <div>{ ReactHtmlParser(html) }</div>;
  }
}

Here's how you can do it, without using dangerouslySetInnerHTML.

import React from "react";

let getNodes = str =>
  new DOMParser().parseFromString(str, "text/html").body.childNodes;
let createJSX = nodeArray => {
  return nodeArray.map(node => {
    let attributeObj = {};
    const {
      attributes,
      localName,
      childNodes,
      nodeValue
    } = node;
    if (attributes) {
      Array.from(attributes).forEach(attribute => {
        if (attribute.name === "style") {
          let styleAttributes = attribute.nodeValue.split(";");
          let styleObj = {};
          styleAttributes.forEach(attribute => {
            let [key, value] = attribute.split(":");
            styleObj[key] = value;
          });
          attributeObj[attribute.name] = styleObj;
        } else {
          attributeObj[attribute.name] = attribute.nodeValue;
        }
      });
    }
    return localName ?
      React.createElement(
        localName,
        attributeObj,
        childNodes && Array.isArray(Array.from(childNodes)) ?
        createJSX(Array.from(childNodes)) :
        []
      ) :
      nodeValue;
  });
};

export const StringToJSX = props => {
  return createJSX(Array.from(getNodes(props.domString)));
};

Import StringToJSX and pass the string in as props in the following format.

<StringToJSX domString={domString}/>

PS: I might have missed out on a few edge cases like attributes.

I came across this answer recently and, it was a good deal for me. You don't need to provide a string. Returning an array of JSX elements will do the trick.

We can store JSX elements in JavaScript array.

let arrUsers = [<li>Steve</li>,<li>Bob</li>,<li>Michael</li>];

and in your HTML (JSX) bind it like,

<ul>{arrUsers}</ul>

As simple as it is.

Use React-JSX-Parser

You can use the React-JSX-Parser library dedicated for this.

npm install react-jsx-parser

here is the repo

Here's a little utility component for this:

const RawHtml = ({ children="", tag: Tag = 'div', ...props }) =>
  <Tag { ...props } dangerouslySetInnerHTML={{ __html: children }}/>;

Sample usage:

<RawHtml tag={'span'} style={{'font-weight':'bold'}}>
  {"Lorem<br/>ipsum"}
</RawHtml>

html-react-parser is what you need.

import parse from 'html-react-parser';
import React from 'react';

export default function YourComponent() {
    someHtml = '<div><strong>blablabla<strong><p>another blbla</p/></div>'
     
    return (
        <div className="Container">{parse(someHtml)}</div>
    )
}

First you can change it to a non-string array and then use it as JSX

class ObjReplicate extends React.Component {
  constructor(props) {
    super(props);
    this.state = { myText: '' };
  }
  
  textChange=(e) =>{this.setState({ myText: e.target.value })};

  render() {
    const toShow = this.state.myText;
    var i=1;
    var allObjs=new Array;
    while (i<100){
      i++;
      allObjs[i] = <p>{toShow}</p>; //non-sting array to use  in JSX
   }
   
    return (
      <div>
        <input onChange={this.textChange}></input>
        {allObjs}
      </div>
   );
  }
}

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