看见Called setState() on an Unmounted Component在您的控制面板是直面后辈化学反应最常用的难题众所周知。当您采用类模块时,您能随心所欲地建立碰到此严重错误的情形。
预览已从 DOM 中删掉的模块的状况一般来说说明您的插件存有缓存外泄。这会节约采用者的Xen,假如不马萨省,将引致操控性渐渐上升。这是再次出现严重错误的其原因和您能采行的举措来化解它。
两个单纯的模块
这是两个基本上的 Re
import React from “react”; class NewsList extends React.Component { state ={ news: null }; componentDidMount(){ fetch(“http://example.com/news.json”).then(res =>{ this.setState({news: response.json()});}).catch(e =>{ alert(“Error!”);});} render(){ if (!this.state.news) return “Loading…”; else return news.map((story, key)=>
{story.Headline}
);} }该模块存有造成called setState() on an unm
当互联网允诺须要一两年就可以化解时,就会再次出现此难题。假如有许多新闻报道因此采用者采用不稳定的3G 相连,则可能将须要几秒的天数。在此之后,采用者可能将早已舍弃并点选了另两个网页。这将装载NewsList并将其从 DOM 中删掉。
虽然展开了导航系统,但互联网允诺仍在展开中。最后它会化解因此它的.then()反弹会运转。依照严重错误最新消息,setState()在装载的NewsList实例上初始化。
现在,您将新闻报道列表存储在未加装模块的状况,这是在节约缓存。数据永远不会被用
化解难题
这个例子的难题很容易化解。这是两个非常基本上的方法:
class NewsList extends React.Component { mounted: false; state ={ news: null }; componentDidMount(){ this.mounted = true; fetch(“http://example.com/news.json”).then(res =>{ if (this.mounted){ this.setState({news: response.json()});} }).catch(e =>{ alert(“Error!”);});} componentWillUnmount(){ this.mounted = false;} }
现在,除非模块仍然挂载,否则 API 初始化的结果将被忽略。当模块即将装载时,React 初始化componentWillUnmounted().模块的mounted实例变量被设置为false,允许fetch反弹知道它是否相连到 DOM。
这有效,但添加了样板代码以跟踪mounted状况。互联网初始化也将运转完成,可能将会节约带宽。这是两个更好的替代方案,它采用anAbortController在fetch中途取消呼叫:
class NewsList extends React.Component { abortController = new AbortController(); state ={ news: null }; componentDidMount(){ fetch(“http://example.com/news.json”,{signal: this.abortController.signal}).then(res =>{ this.setState({news: response.json()});}).catch(e =>{ if (e.name ===”AbortError”){ // Aborted as unmounting } else alert(“Error!”);});} componentWillUnmount(){ this.abortController.abort();} }
现在,该fetch初始化会收到AbortSignal可用于取消允诺的。当 React 将要装载模块时,abort()会初始化abort 控制器的方法。这将反映在传递给的信号中fetch,浏览器将处理互联网允诺的取消。该.then()反弹不会跑得那么你的模块将不会尝试装载后预览其状况。
其他可能将的其原因
此严重错误的另两个常用其原因是当您向模块添加事件侦听器或计时器但在即将装载时未清除它们时:
class OfflineWarning extends React.Component { state ={online: navigator.onLine}; handleOnline =()=> this.setState({online: true}); handleOffline =()=> this.setState({online: false}); componentDidMount(){ window.addEventListener(“online”, this.handleOnline); window.addEventListener(“offline”, this.handleOffline);} render(){ return (!this.state.online ?”Youre offline!”: null);} }
假如采用者移动到不呈现的屏幕,则当他们的互联网条件再次出现变化时OfflineWarning,您将收到called setState()严重错误最新消息。虽然该模块不再挂载,但它配置的浏览器事件侦听器仍将处于活动状况。
采用者可能将会在有屏幕OfflineWarning和没有屏幕的屏幕之间来回移动几次。这将引致存有多个不可见的模块实例,所有这些实例都冗余地侦听互联网事件。
您能通过在装载模块时单纯地反转操作来化解此难题:
class OfflineWarning extends React.Component { componentDidMount(){ window.addEventListener(“online”, this.handleOnline); window.addEventListener(“offline”, this.handleOffline);} componentWillUnmount(){ window.removeEventListener(“online”, this.handleOnline); window.removeEventListener(“offline”, this.handleOffline);} }
采用计时器和间隔时采用相同的模型。假如您setTimeout()或setInterval()您的模块的任何地方,你应该clearTimeout()和clearInterval()它装载了。
覆盖 setState()函数
另一种选择是建立您自己的基础模块来覆盖setState():
class SafeComponent extends React.PureComponent { mounted = false; componentDidMount(){ this.mounted = true;} componentWillUnmount(){ this.mounted = false;} setState(state, callback){ if (this.mounted){ super.setState(state, callback);} }}
任何setState()在异步反弹中初始化的模块都能从SafeComponent而不是React.PureComponent.在SafeComponent父跟踪您的模块的加装是否。setState()假如在装载时收到初始化将被忽略。
这种方法并没有真正化解难题的根源。它能有效地抑制控制面板严重错误并避免装载状况预览,但不应用来代替正确清除计时器和事件侦听器。
虽然如此,当您不熟悉有许多难题的代码库时,此选项能作为权宜之计。对于源自您认为不须要正确中止的次要互联网允诺的严重错误,它也可能将是可接受的化解方案。假如您对在采用者离开屏幕后接收和丢弃数据感到满意,采用自定义基本上模块能避免向每个模块添加重复的“已加装”逻辑。
假如您确实选择了这条路线,请记住在您覆盖这些方法时在您的子模块中初始化super.componentDidMount()和super.componentWillUnmount()。否则该mounted属性将无法正确设置。忘记初始化super.componentDidMount()将意味着mountedalways false,引致每个状况预览都被忽略!
概括
called setState() on an unmounted component在浏览器控制台中看见意味着从 DOM 中删掉模块后,异步操作的反弹仍在运转。这说明由于执行冗余工作而引致缓存外泄,而采用者永远不会由此受益。
您能通过componentWillUnmounted()在模块之后实施和正确清理来化解这些难题。中止未完成的互联网允诺、删掉事件侦听器并取消您建立的任何计时器。这将确保将来没有剩余的代码能运转,因此您的模块在从 DOM 中消失后无需停留并尝试预览其状况。
#知识创作官#
想