I am using React\'s setState
method, and calling another function when the state has been updated.
Is there a preferred approach as to how to call the f
Both of the approaches below work but is there any performance implications of using one over the other?
There's a correctness implication: The first one is incorrect, the second one is correct. :-)
In your first example, you're calling this.clearResult(500)
and then calling setState
(with the result of calling this.clearResult(500)
— undefined
, in your example — as its second argument). this.setState(prevState => { ... }, this.clearResult(500));
is just like foo(bar())
— first it calls bar
, then it passes the result of calling it into foo
.
In your second example, you're passing a function into setState
that it will call when the state is updated.
You want the second form (or one of the various equivalents to it).
this.setState(prevState => {
return {
result: '1-1',
}
}, () => this.clearResult(500));
// or: }, this.clearResult.bind(this, 500));
// But the arrow is clear and idiomatic
Here's proof that your first example is calling clearResult
before calling setState
, and before your state change callback is called:
class Example extends React.Component {
constructor(...args) {
super(...args);
this.state = {value: "a"};
}
// Overriding it PURELY to show what's happening
setState(...args) {
console.log("setState called");
return super.setState(...args);
}
componentDidMount() {
this.setState(
() => {
console.log("state change callback");
return {value: "b"};
},
this.clearResult(500)
);
}
clearResult(delay) {
console.log("clearResult called");
setTimeout(() => {
this.setState({value: "c"});
}, delay);
}
render() {
return <div>{this.state.value}</div>;
}
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
whereas with () => this.clearResult(500)
instead, clearResult
is called after setState
(and after the state change):
class Example extends React.Component {
constructor(...args) {
super(...args);
this.state = {value: "a"};
}
// Overriding it PURELY to show what's happening
setState(...args) {
console.log("setState called");
return super.setState(...args);
}
componentDidMount() {
this.setState(
() => {
console.log("state change callback");
return {value: "b"};
},
() => this.clearResult(500)
);
}
clearResult(delay) {
console.log("clearResult called");
setTimeout(() => {
this.setState({value: "c"});
}, delay);
}
render() {
return <div>{this.state.value}</div>;
}
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Side note 1: If you want, you can be a bit more concise:
this.setState(
() => ({ result: '1-1' }),
() => this.clearResult(500)
);
Side note 2: There's no need to use the function form if the new state you're passing isn't based on current state or props. In your example, it isn't, so yours is one of the places where using the non-callback form is okay:
this.setState(
{ result: '1-1' },
() => this.clearResult(500)
);
That would not be okay if you were using something from this.state
or this.props
. In that situation, use the callback form and its prevState
and props
parameters. Always. And there's little harm in always using the callback form, the overhead of a function call is exceptionally trivial on modern JavaScript engines. (It was even trivial on the slowest JS engine of this century: The one in IE6.)
More on that here and here.