React中,因為非同步操作的關係,組件銷毀後調用了setState(),報警告,怎麼解決?

componetWillMount() {
fetch(url).then((data) =&> {
return data.json();
}).then((res) =&> {
this.setState({
....
})
});
}

我在componetWillMount中訪問了介面返回數據後,調用了setState,訪問的時候按了後退,導致還沒收到響應就銷毀了組件 ,但是fetch請求沒被結束掉,之後 收到響應就調用了setState(),發出警告。請問這種情況該怎麼處理?在unmount中結束fetch嗎?但fetch怎麼結束呢?官方文檔好像沒有api


正確的做法是不要在請求callback里setState,用不會被卸載的組件請求然後用props分發下來數據。

這也是為什麼Redux或者Mobx流行的原因,只用React基本就要踩到這種坑,因為除了最頂層的組件,有幾個組件是真的不會被卸載的呢?

如果實在沒辦法臨時解決,只能加個this.isUnmount,在componentWillUnmount設置為true,然後在fetch callback里判斷如果this.isUnmount不為true的時候再setState。

另外,Facebook以前有篇blog說過這個,以前有個isMounted方法。isMounted is an Antipattern - React Blog

這裡面還有cancellable promise的方法,不建議使用。最好將promise當作不可變的,這樣心智模型比較簡單。


fetch現在還不能取消(相關討論:Aborting a fetch: The Next Generation · Issue #447 · whatwg/fetch),如果你在component life cycle裡面進行非同步操作會遇到setState warning。

解決方案有幾個:

  • 自己封裝一個cancelable Promise,在unmount的時候cancel掉。
  • 對於通用數據抽到redux的store里用connect傳props。
  • 使用rxjs對非同步做subscribe,unmount的時候dispose掉。
  • 在非同步setState之前做mount判斷。
  • 如果你確認這個非同步setState沒有侵入性,也可以不理它。warning的目的在於讓開發者確認自己的編碼存在潛在的問題,在prod下是不報的。


有個this.isMounted屬性可以判斷當前組件是否掛載,你可以在setState之前做一下判斷。

這確實是個坑,但我覺得這本身也不是react應該負責的。合情合理,組件掛載的時候設置了什麼,在卸載的時候最好清理一下,最常見的還有定時器。

看了場電影,隨手帶走垃圾。

非同步請求發起後不能撤銷的這個鍋react不背~不過應該提供解決方案,判斷isMounted再setState,就是一種解決方案。


用redux.

React的props vs state是一個大坑。

用了redux, 世界就清凈了。組件根本不要再用state, 狀態只依靠props。組件要改變狀態,一律通過dispatch執行action, reducer改變store,redux再自動map store到組件的props.

用了redux, 你永遠不需要call setState()


之前也對這個問題困惑,都說redux包治百病,可是也不能什麼都放到store里,必須一個安裝的狀態,不好管理。

然後又試了一種,寫一個decorator,擴展組件的componentWillUnmount, 讓其卸載組件時,覆蓋this.setState為一個自定義空函數。


原因是在非同步操作中setState了,普遍的兩種做法:1.自己打個標記this.ismounted,unmount生命周期里設置為true,在非同步里先判斷下在執行setState。2.用redux之類的flux管理狀態。


雖然不贊同放fetch到life cycle裡面不過你可以unmount裡面cancel fetch


程序員為什麼要在乎warning?


推薦閱讀:

學習react 有哪些瓶頸需要克服?
目前react的生態系統是什麼情況,有沒有比較公認的成熟的開發技術棧?
前端路上,我不知道該如何走了???
如何看待Typescript中的重載(Overload)?
如何看待json語法中不能加註釋的設計?

TAG:Web開發 | JavaScript | React |