0

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 (i.e 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.

davegravy
  • 888
  • 11
  • 28

2 Answers2

0

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.

Rallen
  • 2,240
  • 20
  • 22
0

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.

xadm
  • 8,219
  • 3
  • 14
  • 25