See here: https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html And also here: How to cancel a fetch on componentWillUnmount And here: ismounted antipattern, track own property
In both cases they mention 3 approaches:
promise.resolve
check this.IsMounted()
, which React will return correctly for you, if the `Compounted Has Unmountedpromise.resolve
check _isMounted
, which you have manually tracked in ComponentWillUnmount()
method.promise
doesn't ever resolve. And this will solve all your problems and make it lovely.
Except, in the 3rd case your promise
will error()
, but might also error()
in other cases (e.g. the API is down).
So in reality the 3rd option boils down to:
- In your promise.error
check errorPayload.IsCancelled
, which you have manually tracked in the cancellablePromise
object, which has in turn been triggered by a manual call in ComponentWillUnmount
.
So all three are pretty much identical:
When you are handling your
promise
outcomes, check the value of this variable that is directly tied to whether the component has alreadyunmounted
.
Why do they assert that the 3rd option is better than the other 2, and that the 1st option is an antipattern.
The key element here is that if (this.isMounted()) { setState(...) }
is an antipattern in general. It can lead to the supression of useful warnings, and so its appearance should be treated with suspicion since, in the majority of cases, it represents an opportunity to mask real issues. As such, even in cases where its behaviour is functionally the same as some other approach, that other approach is preferable.
In the case of API calls, it is entirely reasonable that you might want to ignore the results of a promise because it is no longer relevant. The use of a canceled promise syntactically and semantically ties the logic of whether to ignore the result specifically to the API call, which prevents any possibility of future developers accidentally making use of the code in another context and potentially supressing meaningful warnings.
Though the difference may be semantic, the semantics themselves have value to maintainability. In this case, the cancelable promise serves to structurally colocate concerns, attaching a behaviour that can be a problem in general to the specific situation in which it is okay.
isMounted
component method is deprecated. It cannot be used anymore in React 16.
There is no built-in _isMounted
state, it should be defined by the user in component lifecycle hooks. It's a matter of preference to some degree. The problem with it is that it requires promise chain to be coupled to component instance to be able to access this._isMounted
.
This is not a problem for cancellable promises. Even more, this pattern allows to actually cancel asynchronous process, e.g. Axios actually cancels XHR request during cancellation. Still, in order to make this work, this requires the entire promise chain to be cancellation-aware. This may be tedious since cancellation isn't supported in native promises, including async..await
.
Observables provide even more powerful ways to control the execution. There is a single point (a subscription) that is capable to cancel the entire chain by calling unsubscription function:
const unsubscribe = fetchData()
.mergeMap(asynchronousProcessing)
.mergeMap(yetAnotherAsynchronousProcessing)
.subscribe(data => this.setState(data));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With