Browse Source

Added anti-pattern CodeSandbox demo link

main
Brian Vaughn 7 years ago
parent
commit
70e0076c44
  1. 2
      content/blog/2018-06-07-when-to-use-derived-state.md
  2. 87
      examples/when-to-use-derived-state/derived-state-anti-pattern.js

2
content/blog/2018-06-07-when-to-use-derived-state.md

@ -75,7 +75,7 @@ For the simple example above, we could "fix" the problem of unexpected rerenders
/>
```
The above example binds the validation callback inline and so it will pass a new function prop every time it renders- effectively bypassing `shouldComponentUpdate` entirely. [Here is a demo](TODO) that uses a timer to illustrate this problem. Since you can't prevent others from using your component this way, it's inherently fragile.
The above example binds the validation callback inline and so it will pass a new function prop every time it renders- effectively bypassing `shouldComponentUpdate` entirely. [Here is a demo](codesandbox://when-to-use-derived-state/derived-state-anti-pattern) that uses a timer to illustrate this problem. Since you can't prevent others from using your component this way, it's inherently fragile.
Hopefully it's clear by now why unconditionally overriding state with props is a bad idea. But what if we were to only update the state when the email prop changes? We'll take a look at that pattern next.

87
examples/when-to-use-derived-state/derived-state-anti-pattern.js

@ -0,0 +1,87 @@
import React, {Fragment, PureComponent} from 'react';
import {render} from 'react-dom';
// This component illustrates a getDerivedStateFromProps anti-pattern.
// Don't copy this approach!
class ExampleInput extends PureComponent {
state = {
text: this.props.text,
};
// This lifecycle will be re-run any time the component is rendered,
// Even if props (or props.text) have not changed.
// For this reason, it should not update state in the way shown below!
static getDerivedStateFromProps(props, state) {
if (props.text) {
// This return would override state,
// Erasing anything the user typed since the last render.
return {text: props.text};
}
return null;
}
render() {
return (
<input
onChange={this.handleChange}
value={this.state.text}
/>
);
}
handleChange = event =>
this.setState({text: event.target.value});
}
// This component uses a timer to simulate arbitrary re-renders.
// In a real application, this could happen for a variety of reasons:
// Event handlers that call setState, Flux updates, network responses, etc.
class Timer extends PureComponent {
state = {
count: 0,
};
componentDidMount() {
this.interval = setInterval(
() =>
this.setState(prevState => ({
count: prevState.count + 1,
})),
1000
);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
// Binding the validat function inline, as is done below,
// Causes a new function value to be passed each time we render.
// Even though ExampleInput is a PureComponent,
// Its shouldComponentUpdate() will always return true because of this.
// The same would be true of inline objects (e.g. styles) or arrays.
return (
<Fragment>
<p>Type in the box below:</p>
<ExampleInput
exampleFunctionProp={this.exampleInstanceMethod.bind(
this
)}
text="example@google.com"
/>
<p>
Each time the render count ({this.state.count}) is
updated, the text you type will be reset. This
illustrates a derived state anti-pattern.
</p>
</Fragment>
);
}
exampleInstanceMethod(text) {
// ...
}
}
render(<Timer />, document.getElementById('root'));
Loading…
Cancel
Save