卸载组件时对 setState 做出反应警告
Posted
技术标签:
【中文标题】卸载组件时对 setState 做出反应警告【英文标题】:React warning on setState when unmounting component 【发布时间】:2018-03-20 00:36:58 【问题描述】:当我执行以下代码时(参见下面的 sn-p),我收到警告:
警告:setState(...):只能更新已安装或正在安装的组件。这通常意味着您在未安装的组件上调用了 setState()。这是一个无操作。请检查 Blinker 组件的代码。
在我的 Mounter 类下的 componentWillUnmount() 方法中我做错了什么吗?谢谢!
class Blinker extends React.Component
constructor(props)
super();
this.state =
appear: true
this.blinker = this.blinker.bind(this);
blinker()
this.setState(appear: !this.state.appear );
componentDidMount()
setInterval(this.blinker, 300)
render()
return (
<div>
(this.state.appear) && "xxx"
</div>
);
class Mounter extends React.Component
constructor(props)
super();
this.state =
render: true
;
this.interval = null;
componentDidMount()
this.interval = setTimeout( () =>
this.rendering(), 1500
);
componentWillUnmount()
clearInterval(this.interval);
rendering()
this.setState( render: !this.state.render );
render()
return (
<div>
<h1>
this.state.render && <Blinker />
</h1>
</div>
);
ReactDOM.render(<Mounter />, app);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
【问题讨论】:
您的 sn-p 不会发出警告。我不确定这是否相关,但您在setTimeout
函数上调用 clearInterval
。你的意思是打电话给clearTimeout
吗?
【参考方案1】:
清除this.interval
并在设置状态之前检查它。这将防止在卸载组件时设置状态。
componentWillUnmount()
clearInterval(this.interval);
this.interval = null; // clear
rendering()
// this.interval will be null when unmounting so avoid setting state:
if (this.interval)
this.setState(
render: !this.state.render
);
【讨论】:
【参考方案2】:计时器方法可能很棘手,因为它们可能在componentWillUnmount
触发之前触发,但状态设置可能在组件卸载后发生,因为setState
是异步的。要解决这个问题,您可以使用react-timer-mixin。
反应定时器混合
使用裸 setTimeout、setInterval、setImmediate 和 requestAnimationFrame 调用是非常危险的,因为如果你忘记 在卸载组件之前取消请求,您将面临风险 回调抛出异常。
如果您包含 TimerMixin,那么您可以将您的调用替换为
setTimeout(fn, 500)
和this.setTimeout(fn, 500)
(只需在前面加上this
.) 一切都会为您妥善清理。
【讨论】:
我认为在这种情况下没有必要向您的应用程序添加依赖项。检查保存的间隔 ID 就足够了,而且代码量更小。 @Scott 感谢您的输入,但这是一种处理计时器的反应建议方式,所以我认为我应该建议这样做。尽管您的解决方案在大多数情况下都很好,但仍然有很小的机会收到警告,因为setState
可以在将来的任何时间完成,如docs 所述。可以在 if 语句之后和 setState 调用之前卸载组件。
javascript 是单线程的,因此无法在 if 语句之后和 setState 调用之前卸载组件。以上是关于卸载组件时对 setState 做出反应警告的主要内容,如果未能解决你的问题,请参考以下文章
如何切换 css 类以与 setState Hook 做出反应