Converting HTMLElement to a React Element, and keeping any event listeners

Viewed 6266

Rendering some JSON data into a set of collapsible HTML elements is EASY using a library like renderjson (npm package) for Vanilla JS

const data = { sample: [1, 2, 3, 4], data: { a: 1, b: 2, c: ["hello", null] } };
const rjson = renderjson(data);
document.getElementById('to-render').append(rjson);

In The react world

However, renderjson returns an HTMLElement, NOT A STRING. Please note that I'm not JUST trying to convert HTML strings into react HTML here. I'm trying to convert the HTMLElement into a real ReactElement.

So, I actually managed to do this, but since I'm parsing the HTMLElement into a string, all the onClick event listeners generated by renderjson on the + and - handles (to open or collapse the json) are LOST in the process....

Does anyone have any idea on how to convert a HTMLElement object into React Element, keeping all the original event handlers?


I guess, the real question here is: how can the renderjson package be "repackaged" to become React friendly?

Here is a codesandbox to make it easier to see what I'm talking about here.

1 Answers

Good question, I keep running into similar issues with non-React JS libraries that return DOM elements. These libraries should be ported to React, but if you don't want to do that, you can use findDomNode() to get a DOM (not React) node, and append your HTMLElement there. Please note that in the official docs, its use is discouraged because "it pierces the component abstraction". Anyways, in your example, you could add a wrapper class:

class JsonTreeWrapper extends Component {
  componentDidMount() {
    const renderedJson = renderjson(this.props.data);

    const container = findDOMNode(this);
    container.appendChild(renderedJson);
  }

  render() {
    return <div/>;
  }
}

what this does is render a div, and when the component mounts it finds the div and adds the HTMLElement generated by your library there. Simple.

In your App, you can use it like this:

class App extends Component {
  render() {
    return (
      <div>
        <h1> Inside the react world </h1>
        <JsonTreeWrapper data={data}/>
      </div>
    );
  }
}

This way your listeners will be working just fine.

Codesandbox didn't work for me, but you can check a demo here. I hope this helps!

Related