简体   繁体   中英

How to control a non-React component (BokehJS) in React?

Backstory
I want to include a BokehJS plot in my React component. The process for this is to render <div id="my_plot_id" className="bk-root"/> and call window.Bokeh.embed.embed_item(plotData, 'my_plot_id') which injects needed HTML into the DOM.

Because I want to control the BokehJS plot using the React component's state (ie replace the plot with new generated plot data), I don't want to just call embed_item() in componentDidMount() . I've instead placed embed_item() in render() and added some code to remove child nodes of the container div prior to this call.

Problem
My React component renders 3 times on page load and although by the final render I have only one plot displayed, there is a brief moment (I think between the 2nd and 3rd/final render) where I see two plots.

Code

render()
  {
    let plotNode = document.getElementById('my_plot_id');    
    console.log(plotNode && plotNode.childElementCount);

    while (plotNode && plotNode.firstChild) {
      //remove any children
      plotNode.removeChild(plotNode.firstChild);
    }

    const { plotData } = this.state;
    window.Bokeh.embed.embed_item(plotData, 'my_plot_id');

    return(
      <div id="my_plot_id" className="bk-root"/>
    )
  }

In console I see:

null
0
2

Question
So it seems embed_item executes twice before the my_plot_id children are correctly detected.

Why is this happening and how can I resolve it? While the triple render may not be performance optimized I believe my component should be able to re-render as often as it needs to (within reason) without visual glitching like this, so I haven't focused my thought on ways to prevent re-rendering.

Interaction with DOM elements should never happen inside the render method. You should initiate the library on the element using the lifecycle method componentDidMount , update it based on props using componentDidUpdate and destroy it using componentWillUnmount .

The official React documentation has an example using jQuery which shows you the gist of how to handle other dom libraries.

At start plotNode is unable to reach 'my_plot_id' .

You can render null at start, when plotData is unavailable.

You can use componentDidUpdate() .

In this case I would try shouldComponentUpdate() - update DOM node and return false to avoid rerendering.

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