react 記憶體洩露常見問題解決方案
- 在寫 react 程式碼的時候經常遇到如下的報錯
Can't perform a React state update on an unmounted component. This is a no-op...... 複製程式碼
- 本篇文章首先回顧一下什麼是記憶體洩露,然後看兩個 demo 觀察 react 出現記憶體洩露的具體情況。
什麼是記憶體洩露
-
程式的執行需要記憶體。只要程式提出要求,作業系統或者執行時(runtime)就必須供給記憶體。
-
對於持續執行的服務程序(daemon),必須及時釋放不再用到的記憶體。否則,記憶體佔用越來越高,輕則影響系統性能,重則導致程序崩潰。
-
不再用到的記憶體,沒有及時釋放,就叫做記憶體洩漏(memory leak)。
JavaScript 中常見的幾種記憶體洩露
- 全域性變數引起的記憶體洩漏
function leaks(){ leak = '***'; //leak 成為一個全域性變數,不會被回收 } 複製程式碼
- 閉包引起的記憶體洩漏
var leaks = (function(){ var leak = '***';// 被閉包所引用,不會被回收 return function(){ console.log(leak); } })() 複製程式碼
- dom清空或刪除時,事件未清除導致的記憶體洩漏
document.querySelector("#demo").addEventListener('click', myFunction); var para1=document.querySelector("#demo"); para1.parentNode.removeChild(para1); 複製程式碼
如果我們在沒有取消 click 方法前去銷燬了 para1 節點,就會造成記憶體洩露。
正確的做法:
document.querySelector("#demo").addEventListener('click', myFunction); // 我們需要在刪除節點前清除掛載的 click 方法 document.querySelector("#demo").removeEventListener("click", myFunction); var para1=document.querySelector("p1"); para1.parentNode.removeChild(para1); 複製程式碼
- 延展閱讀,大家有空可以仔細的看看阮一峰老師的相關文章
- www.ruanyifeng.com/blog/2017/0… (阮一峰)
為了更加了解 react 的記憶體洩露問題看看下面幾個 demo
Demo1:
componentWillMount: function () { var onLogin = this.props.onLogin || function () {}, onLogout = this.props.onLogout || function () {}; this.on('authChange', function () { console.log('user authenticated:', this.state.isAuthenticated); return this.state.isAuthenticated ? onLogin(this.state) : onLogout(this.state); }.bind(this)); }, 複製程式碼
-
上面的例子是在 Stack Overflow 上看到的,樓主在
componentWillMount
的時候掛載了authChange
事件,然後 react 出現瞭如下的報錯:
- 意思為:我們不能在元件銷燬後設置state,防止出現記憶體洩漏的情況
需要怎麼解決啦?
- 新增如下程式碼即可
componentWillUnmount: function () { this.off('authChange', this.authChange); this.authChange = null; } 複製程式碼
很明顯這種情況就是在 dom 結構銷燬的時候,事件卻沒有清除導致的記憶體洩漏,所以我們需要在componentWillUnmount
的時候去清除掛載的方法
react 記憶體洩露相關解釋和解決方法
-
這裡就提到了記憶體洩露,當我們在使用事件繫結,setInterval,setTimeOut 或一些函式的時候,但是卻沒有在元件銷燬前清除的時候會造成記憶體洩露。這裡我們手動的再
componentWillUnmount
去清除相關的方法即可。 -
why:
- I would move your function into componentDidMount and add cleanup on componentWillUnmount
- Important: componentWillMount is called on the server and client, but componentDidMount is only called on the client.
- If you’re using eventListeners, setInterval or other functions that needs to be cleaned, put them in componentDidMount. The server will not call componentWillUnmount and is usually the cause of memory leaks.
Demo 2
- 下面這種就是常見的情況:
this.pwdErrorTimer = setTimeout(() => { this.setState({ showPwdError:false }) }, 1000); 複製程式碼
設定了一個timer延遲設定state,然而在延遲的這段時間,元件已經銷燬,則造成此類問題
- 解決方法:
- 利用生命週期鉤子函式:componentWillUnmount
componentWillUnmount(){ clearTimeout(this.pwdErrorTimer); clearTimeout(this.userNameErrorTimer); } 複製程式碼