Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the cancelledPromise pattern considered better than the isMounted() "antipattern" in React?

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:

  • In your promise.resolve check this.IsMounted(), which React will return correctly for you, if the `Compounted Has Unmounted
  • In your promise.resolve check _isMounted, which you have manually tracked in ComponentWillUnmount() method.
  • Use cancellable promises, so that you 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 already unmounted.

Why do they assert that the 3rd option is better than the other 2, and that the 1st option is an antipattern.

like image 789
Brondahl Avatar asked Jan 23 '19 12:01

Brondahl


2 Answers

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.

like image 148
Sam Avatar answered Nov 15 '22 16:11

Sam


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));
like image 34
Estus Flask Avatar answered Nov 15 '22 15:11

Estus Flask