0

I'm using React v16.7 and I'm trying to inject React components into a third party JS library (namely, Highcharts) that requires me to return HTML from a function. Here's what I'm doing right now:

function tooltipFormatter(dataPoint) {
    // ... Calculate props according to the dataPoint here ...
    const mountPoint = document.createElement('div');
    ReactDOM.render(<Tooltip {...tooltipProps} />, mountPoint);
    return mountPoint.innerHTML;
}

And I pass this function in a configuration object, like so:

const config = {
    ...,
    tooltip: {
        ...,
        formatter() {
            return tooltipFormatter(this);
        }
    }
}

The problem I'm having is that mountPoint.innerHTML is empty. I found that ReactDOM.render() sometimes works asynchronously:

ReactDOM.render() currently returns a reference to the root ReactComponent instance. However, using this return value is legacy and should be avoided because future versions of React may render components asynchronously in some cases. If you need a reference to the root ReactComponent instance, the preferred solution is to attach a callback ref to the root element.

While debugging, I did this:

ReactDOM.render(<Tooltip {...tooltipProps} />, mountPoint, () => {
    console.log(mountPoint.innerHTML); // non-empty 
});
console.log(mountPoint.innerHTML);  // empty
return mountPoint.innerHTML;

How can I coerce ReactDOM.render() into working in a synchronous context? The puzzling thing is that return mountPoint.innerHTML has worked in the rest of our application, but it seems that this case is the only place ReactDOM.render() has chosen to render the contents asynchronously.

Berk Özbalcı
  • 3,016
  • 3
  • 21
  • 27
  • I have found some typos where you have two `return`s in your first code block. – Huy Jul 26 '19 at 16:34
  • Is it possible to convert `tooltipFormatter` into an async method? Then you can wrap `React.DOM.render`, which accepts a callback in a function that returns a promise, which you can `await` inside `tooltipFormatter`. – dance2die Jul 26 '19 at 17:43
  • @Huy Thank you, I fixed it. – Berk Özbalcı Jul 26 '19 at 18:04
  • @SungM.Kim I doubt that, since Highcharts is the caller of `config.tooltip.formatter` and that context is probably not an `async` context. – Berk Özbalcı Jul 26 '19 at 18:05

1 Answers1

0

I ended up using

return ReactDOM.renderToStaticMarkup(<Tooltip {...props} />);

since my components are not interactive (no event listeners, and my components aren't stateful).

Although I'm willing to bet Portals can probably solve the problem, I couldn't get the ref of the DOM node that Highcharts renders a tooltip or legend label into.

Berk Özbalcı
  • 3,016
  • 3
  • 21
  • 27