8000 prevent infinite loops on frames · Frank-node/react-plotly.js@d81beb9 · GitHub
[go: up one dir, main page]

Skip to content

Commit d81beb9

Browse files
prevent infinite loops on frames
1 parent ace7dba commit d81beb9

File tree

2 files changed

+32
-15
lines changed

2 files changed

+32
-15
lines changed

README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,24 +74,24 @@ For a full description of Plotly chart types and attributes see the following re
7474

7575
## State management
7676

77-
This is a "dumb" component with no internal state. This means that if a user interacts with the plot, by zooming or panning for example, any subsequent re-renders will lose this information unless it is captured and upstreamed via the `onUpdate` callback prop.
77+
This is a "dumb" component that doesn't merge its internal state with any updates. This means that if a user interacts with the plot, by zooming or panning for example, any subsequent re-renders will lose this information unless it is captured and upstreamed via the `onUpdate` callback prop.
7878

7979
Here is a simple example of how to capture and store state in a parent object:
8080

8181
```javascript
8282
class App extends React.Component {
83-
Plot(props) {
83+
constructor(props) {
8484
super(props);
85-
this.state = {
86-
/* data, layout */
87-
};
85+
this.state = { data: [], layout: {}, frames: [], config: {} };
8886
}
8987

9088
render() {
9189
return (
9290
<Plot
9391
data={this.state.data}
9492
layout={this.state.layout}
93+
frames={this.state.frames}
94+
config={this.state.config}
9595
onInitialized={(figure) => this.setState(figure)}
9696
onUpdate={(figure) => this.setState(figure)}
9797
/>
@@ -102,14 +102,15 @@ class App extends React.Component {
102102

103103
## Refreshing the Plot
104104

105-
This component will refresh the plot via `Plotly.react` if either of the following is true:
105+
This component will refresh the plot via [`Plotly.react`](https://plot.ly/javascript/plotlyjs-function-reference/#plotlyreact) if any of the following are true:
106106

107107
* The `revision` prop is defined and has changed, OR;
108-
* One of `data`, `layout`, `frames` or `config` has changed identity as checked via a shallow `===`.
108+
* One of `data`, `layout` or `config` has changed identity as checked via a shallow `===`, OR;
109+
* The number of elements in `frames` has changed
109110

110-
Furthermore, when called, `Plotly.react` will only refresh the data being plotted if the _identity_ of the data arrays (e.g. `x`, `y`, `color` etc) has changed, or if `layout.datarevision` has changed.
111+
Furthermore, when called, [`Plotly.react`](https://plot.ly/javascript/plotlyjs-function-reference/#plotlyreact) will only refresh the data being plotted if the _identity_ of the data arrays (e.g. `x`, `y`, `marker.color` etc) has changed, or if `layout.datarevision` has changed.
111112

112-
In short, this means that simply adding data points to a trace in `data` or changing a value in `layout` will not cause a plot to update unless this is done immutably via something like [immutability-helper](https://github.com/kolodny/immutability-helper) if performance considerations permit it, or unless `revision` and/or `layout.datarevision` are used to force a rerender.
113+
In short, this means that simply adding data points to a trace in `data` or changing a value in `layout` will not cause a plot to update unless this is done immutably via something like [immutability-helper](https://github.com/kolodny/immutability-helper) if performance considerations permit it, or unless `revision` and/or [`layout.datarevision`](https://plot.ly/javascript/reference/#layout-datarevision) are used to force a rerender.
113114

114115
## API Reference
115116

src/factory.js

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,29 @@ export default function plotComponentFactory(Plotly) {
8383

8484
componentWillUpdate(nextProps) {
8585
if (
86-
(nextProps.revision !== void 0 &&
87-
nextProps.revision === this.props.revision) ||
88-
(nextProps.layout === this.props.layout &&
89-
nextProps.data === this.props.data &&
90-
nextProps.config === this.props.config &&
91-
nextProps.frames === this.props.frames)
86+
nextProps.revision !== void 0 &&
87+
nextProps.revision === this.props.revision
9288
) {
89+
// if revision is set and unchanged, do nothing
90+
return;
91+
}
92+
93+
const numPrevFrames =
94+
this.props.frames && this.props.frames.length
95+
? this.props.frames.length
96+
: 0;
97+
const numNextFrames =
98+
nextProps.frames && nextProps.frames.length
99+
? nextProps.frames.length
100+
: 0;
101+
if (
102+
nextProps.layout === this.props.layout &&
103+
nextProps.data === this.props.data &&
104+
nextProps.config === this.props.config &&
105+
numNextFrames === numPrevFrames
106+
) {
107+
// prevent infinite loops when component is re-rendered after onUpdate
108+
// frames *always* changes identity so fall back to check length only :(
93109
return;
94110
}
95111

0 commit comments

Comments
 (0)
0