React:显示加载器,而背景图像正在加载导致setState错误

时间:2016-08-09 07:01:15

标签: javascript reactjs

我正在尝试创建一个加载背景图像的组件(在同构应用程序中)。在加载图像的同时,我想显示一个微调器但是我一直想出这个错误:

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op.

在init上,加载状态设置为false(因此如果禁用js,则不显示微调器)

constructor (props) {
    super(props);
    this.state = {
        loading: false
    };
}

在componentDidMount上,加载状态设置为true,使用props.src创建图像,加载或错误调用函数时。

componentDidMount = () => {
    this.setState({loading: true});

    this.image = new Image();
    this.image.src = this.props.src;
    this.image.onload = this.handleImageLoaded;
    this.image.onerror = this.handleImageError;
}

这些函数会将加载状态设置为false

handleImageLoaded = () => {
    this.setState({loading: false});
}

handleImageError = () => {
    this.setState({loading: false});
}

如果state为true(这会渲染),渲染函数将显示一个单独的组件Loader,我将在img load上更改内联样式背景。

return (
        <div className={style.wrapper}>
            <div className={style.background} style='background-image:'>
                <Loader loading={this.state.loading} />
            </div>
        </div>
    );

2 个答案:

答案 0 :(得分:2)

这是一个非常常见的问题,错误消息会告诉您或多或少发生了什么 - 您试图在未安装的组件上调用setState。在componentDidMount中,您开始加载图像,并设置回调(handleImageLoaded)以在图像加载(或错误)时执行。在此回调中,您拨打setState。由于加载是异步的,因此当组件不再存在于文档中时,它可以很容易地完成。

处理此问题的方法曾经是在修改状态之前询问组件是否仍然加载:

handleImageLoaded = () => {
    if(this.isMounted())
       this.setState({loading: false});
}

不幸的是,现在这会给你一个警告,说isMounted()已被弃用。你现在应该做的就是这个:

{
    isStillMounted: true,
    componentWillUnmount: () => { this.isStillMounted = false; },
    handleImageLoaded: () => {
        if(this.isStillMounted)
            this.setState({loading: false});
    }
}

理想情况下,您只需取消componentWillUnmount中的加载,但我认为不可能。

另外,就像1ven指出的那样,如果您使用的是本机事件而不是React事件,最好在componentWillUnmount中删除这些处理程序,以防止任何潜在的内存泄漏。

答案 1 :(得分:0)

在大多数情况下,在未安装的组件中调用setState时会显示此错误。

在您的情况下,据我所知,出于某种原因,在您加载图片之前,您的组件已卸载。

要避免此错误,应始终删除未在render函数中定义的任何事件侦听器,如下所示:

this.image.onload = undefined;
this.image.onerror = undefined;