[英]React updating state after component has been unmounted (memory leak)
我正在構建一個反應應用程序(我是 javascript 的菜鳥),並且在卸載組件后嘗試更新 state 並努力應對反應。
react 應用程序的上下文:作為學校項目的一部分,我必須為一個小型劇院綜合體構建電影票預訂服務,在 web 應用程序的主頁上,我有一個圖像“輪播”,每 5 秒更新一次圖像.
以下是實際操作中的主頁: https://apollo-9dd16.web.app/
(圖像加載時間只是因為我選擇了相當大的圖像,將被修復) - 首次訪問頁面時的加載屏幕也是因為從 firebase 加載所有內容需要很長時間(所有內容都通過 firebase 數據庫動態更新)如果有是一種讓它更快的方法請告訴我
此外,我已經瀏覽了盡可能多的 SO 帖子,每個人都建議在執行 state 更改之前添加檢查組件是否已安裝,我認為我已經完成了嗎?
無論如何,關於這個問題,由於某種原因,它會說我有一個 memory 泄漏,因為我試圖在卸載組件 state 后更改它(我無法輕松重現它,但它已經發生了很多次)
import React, {Component} from 'react'
import { Link } from 'react-router-dom'
import MoviesContext from '../contexts/Movies'
/* Todo:
- Work on the transition between movies
- Work on sending the user to the right place on book now button press
*/
class Home extends Component {
static contextType = MoviesContext
state = {
intervalID:0,
index:1,
prevIndex:0,
nextIndex:2,
picList:[]
}
componentDidMount() {
let mounted = true
const posterURLS = [] // eslint-disable-next-line
this.context.map((movies) => {
posterURLS.push(movies.posterURL)
})
this.setState({picList: posterURLS})
if(mounted) {
const newIntervalId = setInterval(() => {
if (this.state.nextIndex + 1 === this.state.picList.length ){
this.setState({
prevIndex: this.state.index,
index: this.state.nextIndex,
nextIndex: 0
})
} else {
this.setState({
prevIndex: this.state.index,
index: this.state.nextIndex,
nextIndex: this.state.nextIndex + 1
})
}
}, 5000);
this.setState(prevState => {
return {
...prevState,
intervalId: newIntervalId,
};
});
}
return () => mounted = false
}
render() {
return (
<div className="font-sans font-light text-theme-white text-4xl z-10 flex justify-center items-center h-screen">
<div className="h-3/4">
<div className="h-full justify-center items-center">
<div className="h-full hidden md:flex">
<img src={this.state.picList[this.state.prevIndex]} alt="this is a movie" className="h-full rounded-2xl -mx-20"/>
<img src={this.state.picList[this.state.nextIndex]} alt="this is a movie" className="h-full rounded-2xl -mx-20"/>
</div>
<div className="absolute inset-10 flex justify-center items-center h-screen">
<img src={this.state.picList[this.state.index]} alt="this is a movie" className="h-3/4 rounded-2xl"/>
</div>
</div>
<div className="absolute inset-0 top-10 flex justify-center items-center">
<Link to="/book" className="bg-theme-light text-theme-black rounded-2xl py-3 px-5 hover:bg-theme-black hover:text-theme-light">Book Now</Link>
</div>
</div>
</div>
)
}
}
export default Home
你非常接近:發生這種情況的原因是因為這段代碼:
/* 1 */ if (mounted) {
/* 2 */ const newIntervalId = setInterval(() => {
/* 3 */ if (this.state.nextIndex + 1 === this.state.picList.length) {
/* 4 */ this.setState({
/* 5 */ prevIndex: this.state.index,
/* 6 */ index: this.state.nextIndex,
/* 7 */ nextIndex: 0,
/* 8 */ });
/* 9 */ } else {
/* 10 */ this.setState({
/* 11 */ prevIndex: this.state.index,
/* 12 */ index: this.state.nextIndex,
/* 13 */ nextIndex: this.state.nextIndex + 1,
/* 14 */ });
/* 15 */ }
/* 16 */ }, 5000);
/* 17 */
/* 18 */ this.setState((prevState) => {
/* 19 */ return {
/* 20 */ ...prevState,
/* 21 */ intervalId: newIntervalId,
/* 22 */ };
/* 23 */ });
/* 24 */ }
/* 25 */
第 1 行(在上面的代碼段中)的if (mounted)
條件有點太高了。 您應該將 if 語句包裝在第 4 行和第 10 行的setState
調用周圍,因為它們都在setInterval
function 回調中。
目前,代碼說:
但我相信你希望你的代碼說:
if (mounted) {
const newIntervalId = setInterval(() => {
if (this.state.nextIndex + 1 === this.state.picList.length) {
if (mounted) {
this.setState({
prevIndex: this.state.index,
index: this.state.nextIndex,
nextIndex: 0,
});
}
} else {
if (mounted) {
this.setState({
prevIndex: this.state.index,
index: this.state.nextIndex,
nextIndex: this.state.nextIndex + 1,
});
}
}
}, 5000);
this.setState((prevState) => {
return {
...prevState,
intervalId: newIntervalId,
};
});
}
這應該在組件已經卸載后修復組件更新。 您甚至可以刪除上述代碼段開頭的if (mounted)
檢查。
發生這種情況的原因是,在執行componentDidMount
function 時, mounted
變量為true
,因此它將注冊setInterval
回調並每 5 秒執行一次。
雖然執行setInterval
回調時mounted
的變量可能不再為true
,但沒有什么可以阻止它執行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.