为什么在React中认为cancelledPromise模式比isMounted()“反模式”更好?

时间:2019-01-23 12:16:37

标签: javascript reactjs

请参见此处:https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html 还有这里:How to cancel a fetch on componentWillUnmount 在这里:ismounted antipattern, track own property

在两种情况下,他们都提到了3种方法:

  • promise.resolve中选中this.IsMounted(),如果“ Compounted已卸载”,则React将为您正确返回
  • promise.resolve中,选中_isMounted方法中手动跟踪的ComponentWillUnmount()
  • 使用可撤销的承诺,这样您promise永远不会解决。 这将解决您所有的问题并使它变得可爱。

除了在第三种情况下,您的promiseerror(),在其他情况下(例如,API已关闭)也可能error()

因此,实际上,第三个选项归结为:  -在promise.error中选中errorPayload.IsCancelled中已手动跟踪的cancellablePromise对象,而该对象又是由ComponentWillUnmount中的手动调用触发的。

所以这三个几乎完全相同:

  

在处理promise结果时,请检查与该组件是否已经unmounted直接相关的变量值。

为什么他们断言第三个选项比其他两个更好,而第一个选项是反模式。

4 个答案:

答案 0 :(得分:4)

这里的关键元素是if (this.isMounted()) { setState(...) }通常是反模式 。它可能导致压制有用的警告,因此应该以怀疑的态度对待它,因为在大多数情况下,它代表了掩盖实际问题的机会。因此,即使在行为上与其他方法在功能上相同的情况下,该其他方法也是可取的。

对于API调用,您完全可以忽略一个承诺的结果,因为它不再相关了,这是完全合理的。在语法上和语义上,使用已取消的承诺将是否忽略该结果的逻辑专门与API调用联系在一起,从而避免了将来的开发人员在其他情况下意外使用该代码并可能抑制有意义的警告的可能性。

尽管差异可能是语义上的,但语义本身对可维护性具有价值。在这种情况下,可撤销的承诺可以在结构上定位问题,将可能是一个问题的行为附加到可以实现的特定情况。

答案 1 :(得分:2)

isMounted组件方法已弃用。它不能再在React 16中使用。

没有内置的_isMounted状态,它应该由用户在组件生命周期挂钩中定义。在某种程度上,这是一个优先事项。它的问题在于,它要求将Promise链耦合到组件实例才能访问this._isMounted

对于可撤销的承诺而言,这不是问题。甚至更多,这种模式允许实际取消异步过程,例如Axios实际上在取消过程中取消了XHR请求。尽管如此,为了使这项工作有效,这要求整个承诺链都必须了解取消情况。这可能很乏味,因为本地承诺(包括async..await中不支持取消。

Observables提供了更强大的方法来控制执行。有一个单点(订阅)可以通过调用取消订阅功能取消整个链:

const unsubscribe = fetchData()
.mergeMap(asynchronousProcessing)
.mergeMap(yetAnotherAsynchronousProcessing)
.subscribe(data => this.setState(data));

答案 2 :(得分:0)

因此,让我们从假设我们正在讨论情况'setState()在未安装的组件上被调用'警告开始。

通常,setState()可能有不同的呼叫者

  1. 在组件上设置的事件处理程序
  2. 任何类型的计时器(setImmediatesetIntervalsetTimer
  3. 全局事件处理程序
  4. XHR处理

除了#1之外,所有这些原因都可能产生“在未安装的组件上调用setState”警告。

如果对XHR做出反应,肯定会来得太迟了,这是可以预期的。但是对于#2和#3情况,被isMounted抑制的这种警告只会隐藏您最好解决的实际问题。

因此,通常,这实际上是反模式-抑制被认为可以使您免于错误的东西。

是的,在某些情况下,我们可以确定“这仅适用于XHR”

fetch(....).then(({ items }) => _isMounted() && this.setState({ items }));

但是,迟早有一天,它将进入单独的方法,我们无法控制其调用方式。

无论如何反模式代码气味并不意味着您不能这样做。而是意味着“更好地避免”。所以最终由您决定。特别是如果您出于某些原因使用本地fetch()并找到aborting requests overcomplicated

答案 3 :(得分:-1)

让我们想象一下将导致将来的setState调用的操作将进行大量计算,或者进行大量网络请求。所有这些资源都将被使用,然后在将来诺言解决时,它将意识到不需要所有工作,因为用户已经离开了页面的那一部分,所有工作都将被丢弃。这对性能和网络/内存使用情况不利,尤其是当您有很多元素出现和消失时。如果使用选项3,则只有少量资源被浪费,直到到达下一个停止点并释放资源为止。我认为他们删除了1)迫使代码编写者使用3),并提出了2)用于不可能/难以迁移的情况。