Reputation: 119
When using React I've understood it so that calling setState inside a component's render method is bad practice; instead keep this method pure. However, if I need to update the state based on an event that is linked to a component, how do I do this?
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
The code above is from React's official tutorial. As we can see, an eventhandler is bound to the onClick attribute, and inside this eventhandler the state of the component is changed, so potentially we will update the state while calling from a render method. Thus I am a bit lost as to why this is alright to do but not calling setState explicitly in the render method? Has it to do with how React wraps plain html-events?
Upvotes: 2
Views: 7791
Reputation: 1682
What is bad practice is to call setState
explicitly in the render method, because the render method should be able to run multiple times without having any side effects (Without affecting anything outside the render itself)
In the code block above, the setState
is bound to a click handler, so that means it is only invoked when the button is clicked, not when the render method is called, so this is completely fine.
To recap:
It is fine to have event handlers that update the state in the render method, as long as they are only called when that event is fired.
It is not good to have setState
or a function that calls setState
directly in the render
function.
EXAMPLE
doSomthing = () => {
this.setState({ foo: 'bar' });
}
render() {
return (
<button onClick={this.doSomething}>Click Me</button>
);
}
// this code is GOOD
The above example is OK
doSomething = () => {
this.setState({ foo: 'bar' });
}
render() {
this.doSomething();
return (
<button>Click Me</button>
);
}
// this code is BAD
The above example is BAD
Upvotes: 3
Reputation: 1119
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
{this.setState(() => ({}))}
);
}
When you are trying to do something like above. It causes rendering issue.
Think what is the purpose of the setState()
. Obviously to change the state of component. Now think what happens when your state changes. Yes your component is rendered again. Now think if a component is rendering and it finds the setState()
again then it will cause the rendering to malfunction.
Now over to your issue of event handler a good practice of using
setState()
It is simple concept, we are using reference in event call that means when the component is rendered it is not going to fire it immediately rather it will wait for someone to call. It is clear that when someone is going to invoke the call then only state is changed and it will cause no issue to render()
and it will work properly
Upvotes: 1
Reputation: 627
there is function not called, only passed :
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
Upvotes: 1