react: Calling setState in render causes infinite loop
This may seem really silly to do to call setState in render. However it’s possible for this to happen if a component has a callback which is being called immediately during render and in your callback handler you call setState.
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Reactions: 1
- Comments: 26 (2 by maintainers)
Commits related to this issue
- Fix infinite pulling of source code Possibly related to this: https://github.com/facebook/react/issues/5591 — committed to inodb/cbioportal-frontend by inodb 7 years ago
I ran into this by accident once… I had
onClick={this.setState({inProgress: true})}instead ofonClick={() => this.setState({inProgress: true})}. It would be nice if React detected the problem and threw an error “setState detected in render() of SomeComponent” instead of going into the infinite loop.The fact that we support calling
setStateincomponentDidMountorcomponentDidUpdateis not an accident – doing so in order to trigger an update is sometimes useful.In general, this should never happen; you should not be doing anything remotely related to modifying any component’s state within a render function.
I’m curious what your use case is, for having a callback which does a setState; mind sharing?
It is absolutely fine to call
setStatefromcomponentDidMountif you have to read something from the DOM. It’s not supposed to be pure. In fact the measurement use case is one of the reasons it exists.React was designed with this use case in mind. There shouldn’t be a blip because React processes
setStatefromcomponentDidMountsynchronously to avoid this problem.There are multiple Child1 and Child2 elements with different values, so no, I don’t know mRecord in the parent. But I figured out my issue: I should have
<button onClick={()=>this.props.init(this.props.mRecord)}/>instead of<button onClick={this.props.init(this.props.mRecord)}/>I have a simple solution, compares the state before you change, it worked for me. I just “setState” the state if the new state is different than the current.
This is an oversimplification of the code but:
When
Fooreceives props it callsonCallbackwhich in turn callshandleSomething. Which will causerenderto be called immediately. Then once againhandleSomethinggets called thenrenderand so on.Again this is an oversimplification and what
Foomight be doing is dumb butreactstill shouldn’t callrenderimmediately aftersetStatein the same reconciliation cycle.I realize this is an old ticket and there might be more idiomatic ways of doing things in React now - but I just hit an issue which is related, so figured here’s as good a place as any to comment 😉
What’s the best way to handle situations where you need to measure after the component has been mounted? I’d prefer to avoid
refbecause there’s no need to actually call the component. Also, when dealing with custom renderers I’m not sure how to implementrefand furthermore - CSS tricks like ‘visible’ may not apply.Here’s an example of what I mean:
The issues I have with this approach are:
It’s bordering on like
setStatewithinrender. Not really since it will only happen the first time via cDM, but still… feels icky with that extra private var and… I dunno… just feels odd?There’s going to be a blip where the wrong position is truly rendered. The only way around this I can think of is to manage it via visual tricks like setting opacity.
I’d love to hear thoughts on why this is or isn’t the right way to do it. Thanks!