I am using React-Plotly to make a scatter plot in a dashboard. There are sibling components to this scatter plot where a user can select a "unit". When a user selects a unit in one of these sibling components, I store the unit ID in global state, and the scatter plot accesses that ID to determine what type of marker to use for each unit.
My dilemma is that the underlying units don't change very frequently, but the selected unit does change frequently. This causes performance issues because multiple scatter plots with tens of thousands of markers re-render every time a new unit is selected. I just need one or two markers to re-render - the one that is newly selected, and any potential previously selected marker.
Is there a way in React-Plotly, or a different charting library, to update one marker without re-rendering the entire scatter plot component? I wish I could feed <Plot />
an array of children marker components that could each access the selectedUnitID
state without having to map over all the units and create a new data array each time. That would save me from accessing selectedUnitID
in the parent, causing the re-render. I do something similar when making maps in React-Leaflet, but I haven't found a comparable solution for charting libraries. They all seem to require passing an array of objects, which is recreated with every unavoidable re-render in this case.
Any help would be greatly appreciated. Thank you!
// ScatterPlot.tsx
export const ScatterPlot = (): JSX.Element => {
const units = useSelector(selectUnits); // Doesn't change often
const selectedUnitID = useSelector(selectSelectedUnitID); // Changes often
const data = units.map(u => {
return {
x: u.x,
y: u.y,
type: "scatter",
mode: "lines+markers",
marker: selectedUnitID === u.id ? selectedMarker : normalMarker
};
return <Plot layout={{ width: 320, height: 240, title: "Units Plot" }} data={data} />
};
I have considered storing the array in a ref.current
and passing the ref down to a memoized <Plot />
component since that will be preserved between re-renders, but that seems a little hacky. I'm wondering if I'm misunderstanding something fundamental here.
Edit:
If I alter the units array in place, I can memoize the <Plot />
element so it doesn't re-render since the array reference won't change. However, then the plot doesn't change when it needs to, so I use the revision prop. But then I'm back at square-one because revision
will change often, re-rendering the entire plot. What I'm really looking for is the ability to re-render just one or two markers.
if i get you correctly ,you want to avoid unnecessary computing on function call on every time there is slight change
in the below block, the
UseMemo
will compare these given dependencies with the previous render state and if there is no changes between any of these dependencies then theuseMemo
will not call the function again so nothing will render again.so try the following block that use
useMemo
but if you pass an empty array [] then the useMemo will only execute the function once on the very first render of the component, and it will keep these value for rest of the lifecycle for this given component .
please read understanding-of-usememo-does-usememo-actually-memoize