How do I convert a string to jsx?
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?
You can consider using the React attribute dangerouslySetInnerHTML
:
class YourComponent{
render() {
someHtml = '<div><strong>blablabla<strong><p>another blbla</p/></div>'
return (
<div className="Container" dangerouslySetInnerHTML={{__html: someHtml}}></div>
)
}
}
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>;
}
}
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.
If you consider string
<div>Hello World</div>
If we are very strict, this actually is the valid JSX. The question is how to compile this JSX string into React code.
Easiest and the recommended way is to download some library like Babel and use it to transform the code. Babel can run in the Browser like the repl does.
It is also possible to transform JSX to other formats, but in this case you have to find a compiler or create one yourself.
The steps to create the JSX => React transformation yourself is:
- transform the code string into AST representation
- parse the AST and output code back to string
So you need somekind of AST parser like espree supporting JSX and then you can create a code which walks the AST tree and outputs something, like React -code out of it.
The AST tree of JSX data consists of normal JavaScript AST together with JSX nodes. The parser should walk through the tree and transform the JSX nodes into normal JavaScript code.
If you compile to React and encounter a JSX node with tag "div" you should compile that into React.createElement("div",...
call with attributes and subnodes found under that AST node inserted as parameters of that call.
I have created a small AST Walker, which can process AST tree, ASTWalker, which can be used to transform the AST tree into some output format, like React or DOM.
On-line example of how to use it is here:
http://codepen.io/teroktolonen/pen/KzWVqx?editors=1010
The main code looks like this:
// here is the JSX string to parse
var codeStr = "<div>Hello world</div>";
var walker = ASTWalker({
defaultNamespace: "react",
});
// compile AST representation out of it.
var rawAST = espree.parse(codeStr, {
ecmaVersion: 6,
sourceType: "script",
// specify additional language features
ecmaFeatures: {
// enable JSX parsing
jsx: true
}
});
// then you can walk the walk to create the code
walker.startWalk( rawAST, {} );
var code = walker.getCode();
console.log(code);
document.getElementById("sourceCode").innerHTML = code;
DISCLAIMER: The library is not intented for compiling into React. It is mostly used with defaultNamespace: "DOM",
using it to compile into plain JavaScript + DOM representation. Trying anything more complicated than simple tags may result as an error.
The important thing is to notice that React is not only possible output format for JSX.
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 => {
const className = nodeArray[0].className;
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.