我正在构建一个react应用程序(我是javascript的专家),并在组件卸载后尝试更新状态。
react应用程序的背景:作为学校项目的一部分,我必须为一个小型剧院综合体建立一个电影票预订服务,在网络应用程序的主页上,我有一个图像"旋转木马",每5秒更新一次图像。
以下是正在运行的主页:https://apollo-9dd16.web.app/
(图像加载时间只是因为我选择了相当大的图像,将被修复)-第一次访问页面时的加载屏幕也是因为从firebase加载所有内容需要很长时间(所有内容都通过firebase数据库动态更新)如果有办法让它更快,请让我知道
此外,我已经浏览了尽可能多的SO帖子,每个人都建议在执行状态更改之前添加一个检查组件是否已安装,我认为我已经做到了?
无论如何,对于这个问题,出于某种原因,它会说我有内存泄漏,因为我试图在组件卸载后更改组件状态(我无法轻松复制它,但它已经发生了很多次)
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
函数回调中。
目前,代码显示:
- 如果安装了组件
- 注册此间隔,每5秒更新一次状态
但我相信你希望你的代码说的是:
- 如果安装了组件
- 每5秒更新一次状态,但前提是组件仍处于安装状态
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
函数时,mounted
变量是true
,因此它将注册setInterval
回调,并保持每5秒执行一次。
当执行setInterval
回调时,mounted
变量可能不再是true
,但没有什么可以阻止它执行。