简体   繁体   中英

How to put React component inside HTML string?

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, on componentDidMount 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 and innerHTML , to convert <MyReactComponent/> to HTML string, combine it with <h1>Hi</h1> , but it destroy any React interaction with <MyReactComponent/> .

You 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-component></x-my-react-component></h1> .

Example:

import { Parser, ProcessNodeDefinitions } from "html-to-react";
import MyReactComponent from "./MyReactComponent";

const customElements = {
    "x-my-react-component": 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-component></x-my-react-component></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 complex 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!

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