在React開發中,我們可能會遇到警告:
Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method”
意思爲:我們不能在組件銷燬後設置state,防止出現內存泄漏的情況。
//組件B class TestContainer extends Component{ constructor(){ super() this.state = { isShow:true } } render(){ return ( <div> <button onClick={()=>this.setState({isShow:!this.state.isShow})}>toggle</button> {!!this.state.isShow&&<Test />} </div> ) } } //組件A class Test extends Component{ constructor(){ super() this.state = { num:0 } } getNum=()=>{ //模擬異步請求 this.timer = setTimeout(()=>{ this.setState({ num: Math.random() }) },3000) } render(){ return ( <div onClick={this.getNum} style = {{ width: 100, height: 100, background: 'red' }}> {this.state.num} </div> ) } } // 在本例子中: // 當我們點擊組件A時,會發送一個異步請求,請求成功後會更新num的值。 // 當我們點擊組件B時,會控制組件的A的卸載與裝載
當我們點擊組件A後,組件A需要3秒的時間才能獲取到數據並重新更新num的值,假如我們在這3秒內點擊一次組件B,
表示卸載組件A,但是組件A的數據請求依然還在,當請求成功後,組件A已經不存在,此時就會報這個警告(大概意思就是:你組件都沒了,你還設置個啥)
解決辦法:
本問題出現的原因就是:我們應該在組件銷燬的時候將異步請求撤銷
- 在componentWillUnmount中撤銷異步請求
-
在axios上有撤銷異步請求的方法,但是我們有這麼多組件,每次都要撤銷豈不是太麻煩了
-
我們可以利用一個‘開關的思想’,在組件銷燬的時候給this上掛載一個屬性,每次發送請求的時候,我們判斷一下這個屬性是否存在(還是麻煩,每次都要判斷)
-
基於思路2,我們不想每次判斷,因此是不是應該將其封裝,利用修飾器對componentWillUnmount和setState進行改裝
function inject_unount (target){ // 改裝componentWillUnmount,銷燬的時候記錄一下 let next = target.prototype.componentWillUnmount target.prototype.componentWillUnmount = function () { if (next) next.call(this, ...arguments); this.unmount = true } // 對setState的改裝,setState查看目前是否已經銷燬 let setState = target.prototype.setState target.prototype.setState = function () { if ( this.unmount ) return ; setState.call(this, ...arguments) } } @inject_unount class BaseComponent extends Component { } //以後我們寫組件時直接繼承BaseComponent
轉載於:https://segmentfault.com/a/1190000017186299