react-plotly.js: Props should not be mutated by Plot component
It seems like the Plot component mutates its props (at least layout
) instead of cloning the data.
Mutation of props is to me unexpected (and undesired) behavior for a react component.
If for instance the layout is stored in the state of a component and then fed to the Plot component as a prop, like
render() {
<Plot
layout={this.state.layout},
...
/>
we will have a problem, since this.state
only should be updated with the react setState()
method.
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 15
- Comments: 17 (13 by maintainers)
@nicolaskruchten
You asked for how this caused a problem in our case, and while the state example I gave was a simple example of where things could go wrong when props are mutated, it perhaps did not describe a realistic scenario very well 😃
The problem we have run into was a bit more complex. But basically we have a page with a list of objects, lets call them processes. When clicking on a process, the user is routed to another page displaying a plotly graph of the process status.
The data comes from a web API through the redux store, while the layout is a template object constant, that only sometimes is modified depending on the data. Both are fed to a Wrapper component containing the plotly Plot component. Going back from the plot page to the list page, the Wrapper and Plot components are unmounted and destroyed.
Now, going to another plot, using the same layout object (which originates higher up in the component tree, and thus not destroyed) we may suddenly have extra properties like selected tool or zoom range (depending on how the user interacted with the last plot) in our newly created plot that we did not expect.
Now that we know that props are mutated, it should be possible to work around until you have a longterm solution to what I understand is a complex problem. However, in the meantime, would it be possible to add this information to the documentation, e.g. in the Plotly component API?
To second @gimbo’s comment, we got only blank space where the plot was supposed to be after refactoring to use redux-toolkit (which uses immer under the hood). This was part of a larger refactoring, so it took some time to figure out the problem — no errors logged, but the debugger revealed it of course.
In this case, the workaround is to disable immer’s auto freeze functionality:
Just a small heads-up…
I’ve just hit this problem using a
Plot
component in a React/Redux app built using the Redux Starter Kit which, it seems, the redux docs will soon be encouraging newcomers to use; that kit includes the redux-immutable-state-invariant package by default (in dev mode anyway), which detects these layout/data mutations and turns them into showstopping errors. (Fortunately I figured out that deep-cloning thelayout
prop “fixed” the problem, which led me to this issue — glad I didn’t spend a couple of hours debugging redux-observable epics, which was my first thought as to the culprit!)Anyway, yeah, you might see more people hitting this in future if Redux Starter Kit gets traction, which I guess it will if the Redux docs point to it, which they almost certainly will…
Thank you for sharing, this makes the problem quite clear. I apologize that our unclear documentation caused you undue issues in tracking this down and I’ll see about making it clearer. In the short run, however, our goal is to actually fix this, obviously 😃
Probably just “here is the final state”, because the instructions would basically be “feed this back to me please” 😃
One thing to note here is that for versions of plotly.js before 1.34, this type of wiring would cause many updates to result in 2
newPlot
calls 😦