Using both getDerivedStateFromError and getDerivedStateFromProps can be a foot gun
See original GitHub issueDo you want to request a feature or report a bug?
Feature
What is the current behavior?
If componentDidCatch
and/or getDerivedStateFromError
put the component in a state that avoids the cause of the error, and getDerivedStateFromProps
reverts that state change, the error boundary will (obviously) fail to avert disaster.
https://codesandbox.io/s/pj0lwxk15j
It sounds very obvious when simplified like this, but when my team updated to React 16.5.x (and 16.6.0), suddenly this started happening for us. So something changed internally, but it’s hard to pinpoint what. Unfortunately I haven’t been able to create a small repro for that specific case that works in 16.4.2 but not 16.5.0 – so I’m making this issue about avoiding the cause in the first place.
What is the expected behavior?
Naively, my thinking is that because errors are more exceptional, let the state from error handlers take precedence. Probably there’s a reason why this can’t happen so a warning of some kind when this can happen would be nice. Two ways to do this comes to mind:
- Cross-check that keys in state from
getDerivedStateFromProps
orsetState
incomponentDidCatch
don’t collide withgetDerivedStateFromError
(sounds a bit far fetched?) - Be more explicit in documentation for error boundaries about how
getDerivedStateFromProps
will run last so that a developer can consider this case
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
16.5.0 and up (16.4.2 behaves a bit differently – see above), all platforms/browsers.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:6 (2 by maintainers)
Fair enough, it should definitely rely on what changes. Given the following scenario, what’s the correct way to set
this.state.error
tonull
whenthis.props.children
changes (eg a property change)?Here’s a sandbox: https://codesandbox.io/s/035nw47kkp
(This indicates a bug in the child component, but it’s a component out of our control and our UI will need to handle it and for good user experience recover once the component has been replaced or updated to work again.)
The options I can think of are:
setState
will only happen once at this level, even as the component renders twice to recover from the error).this.props.children
value that the component had upon error with the current value upon render and only show the error if it’s identity equal to the erroringthis.props.children
.error
) when something further up the stack changes to probethis.props.children
for potential errors and either recover from or retain the error state.I would like to have the componentDidCatch cause an error toast message to occur, but have the application continue rendering. Is it possible to resume the render? I understand that i will need to resolve the state issues myself