I have: an array of HTML strings, eg ["<h1>Hi", "</h1>"
].
I want to place <MyReactComponent/>
in between them
(thus achieving a layout that would be in jsx:
<h1>Hi<MyReactComponent/></h1>
).
How do I achieve this?
I've tried:
Babel.transform('<h1>Hi<MyReactComponent/></h1>')
(using standalone Babel). It does work, but requires me to stringify<MyReactComponent/>
, which is not elegant and probably will break some day.to use regular jsx
render() => <MyReactComponent/>
, and then, onponentDidMount
prepending HTML by manipulating DOM, but browser inserts closing tags automatically, so I'll be getting<h1>Hi</h1><MyReactComponent/><h1></h1>
to use
jsx-to-html
library andinnerHTML
, to convert<MyReactComponent/>
to HTML string, bine it with<h1>Hi</h1>
, but it destroy any React interaction with<MyReactComponent/>
.
I have: an array of HTML strings, eg ["<h1>Hi", "</h1>"
].
I want to place <MyReactComponent/>
in between them
(thus achieving a layout that would be in jsx:
<h1>Hi<MyReactComponent/></h1>
).
How do I achieve this?
I've tried:
Babel.transform('<h1>Hi<MyReactComponent/></h1>')
(using standalone Babel). It does work, but requires me to stringify<MyReactComponent/>
, which is not elegant and probably will break some day.to use regular jsx
render() => <MyReactComponent/>
, and then, onponentDidMount
prepending HTML by manipulating DOM, but browser inserts closing tags automatically, so I'll be getting<h1>Hi</h1><MyReactComponent/><h1></h1>
to use
jsx-to-html
library andinnerHTML
, to convert<MyReactComponent/>
to HTML string, bine it with<h1>Hi</h1>
, but it destroy any React interaction with<MyReactComponent/>
.
-
Have you tried parsing the strings with
React.createElement
to create the DOM? Is this an option or are you looking for generatingjsx
only ? – melc Commented Aug 16, 2016 at 10:09 - it absolutely is an option. – Evgenia Karunus Commented Aug 17, 2016 at 12:28
1 Answer
Reset to default 6You might want to take a look at html-to-react.
This library converts the string to a node tree of DOM elements, then transforms each node to a React element using a set of instructions that you define. I believe that it depends on the string being valid markup though, so you might have to change "<h1>Hi<MyReactComponent/></h1"
to something like "<h1>Hi<x-my-react-ponent></x-my-react-ponent></h1>
.
Example:
import { Parser, ProcessNodeDefinitions } from "html-to-react";
import MyReactComponent from "./MyReactComponent";
const customElements = {
"x-my-react-ponent": MyReactComponent
};
// Boilerplate stuff
const htmlParser = new Parser(React);
const processNodeDefinitions = new ProcessNodeDefinitions(React);
function isValidNode(){
return true;
}
// Custom instructions for processing nodes
const processingInstructions = [
// Create instruction for custom elements
{
shouldProcessNode: (node) => {
// Process the node if it matches a custom element
return (node.name && customElements[node.name]);
},
processNode: (node) => {
let CustomElement = customElements[node.name];
return <CustomElement/>;
}
},
// Default processing
{
shouldProcessNode: () => true,
processNode: processNodeDefinitions.processDefaultNode
}
];
export default class MyParentComponent extends Component {
render () {
let htmlString = "<h1>Hi<x-my-react-ponent></x-my-react-ponent></h1>";
return htmlParser.parseWithInstructions(htmlString, isValidNode, processingInstructions);
}
}
The essential part here is processingInstructions
. Every node in the DOM tree is checked against each instruction in the array, starting from the top, until shouldProcessNode
returns true, and the node is transformed to a React element by the corresponding processNode
function. This allows for rather plex processing rules, but it quickly gets a bit messy if you want to process nested custom elements. The result of the example is the equivalent of
<h1>
Hi
<MyReactComponent/>
</h1>
in JSX syntax. Hope this helps!