警告反应:setState(...):只能更新已安装或正在安装的组件

时间:2019-03-25 14:45:50

标签: javascript reactjs redux

警告:setState(...):只能更新已安装或正在安装的组件。这通常意味着您在未安装的组件上调用了setState()。这是无人操作。

这是一个React应用程序,其中横幅广告固定在屏幕上并传递随机图像。它的编写方式正在生成有问题的警告。

import React from "react";
import Lightbox from "react-image-lightbox";
import logo from "./logo.png";

class Banner extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      images: [],
      currentImage: logo,
      isOpen: false,
      sidebarOpen: true
    };
  }

  async componentWillMount() {
    await this.getBanners();
    this.setState({ currentImage: this.state.images[0].url });

    setInterval(async () => {
      await this.getBanners();
    }, 300000);

    let i = 0;
    setInterval(
      () => {
        this.setState({ currentImage: this.state.images[i].url });
        if (i >= this.state.images.length - 1) {
          i = 0;
        } else {
          i++;
        }
      },
      10000,
      i
    );
  }

  async getBanners() {
    const data = await (await fetch("/api/banners/active")).json();
    if (data.true) {
      this.setState({ images: data.true });
    }
  }

  render() {
    const { isOpen } = this.state;

    return (
      <div>
        {isOpen && (
          <Lightbox
            mainSrc={this.state.currentImage}
            onCloseRequest={() => this.setState({ isOpen: false })}
          />
        )}
        <footer>
          <a>
            <img
              width={270}
              height="200"
              src={this.state.currentImage}
              onClick={() => this.setState({ isOpen: true })}
              alt="idk"
            />
          </a>
        </footer>
      </div>
    );
  }
}

export default Banner;

有人可以帮助改善此代码吗?

2 个答案:

答案 0 :(得分:1)

您可以将setInterval返回的数字放在您的实例上,并在clearInterval中用componentWillUnmount停止间隔,以便在组件卸载后它们不会继续运行。

class Banner extends React.Component {
  constructor(props) {
    super(props);

    this.bannerInterval = null;
    this.currentImageInterval = null;
    this.state = {
      images: [],
      currentImage: logo,
      isOpen: false,
      sidebarOpen: true
    };
  }

  async componentDidMount() {
    await this.getBanners();
    this.setState({ currentImage: this.state.images[0].url });

    this.bannerInterval = setInterval(async () => {
      await this.getBanners();
    }, 300000);

    let i = 0;
    this.currentImageInterval = setInterval(
      () => {
        this.setState({ currentImage: this.state.images[i].url });
        if (i >= this.state.images.length - 1) {
          i = 0;
        } else {
          i++;
        }
      },
      10000,
      i
    );
  }

  componentWillUnmount() {
    clearInterval(this.bannerInterval);
    clearInterval(this.currentImageInterval);
  }

  // ...
}

答案 1 :(得分:0)

将此模板用于任何具有状态的基于类的组件:

忘记了setState(),并使用向下声明的setComponentState:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      // other fields...
      isUnmounted: false,
    };
  }

  componentWillUnmount() {
    this.setState({ isUnmounted: true });
  }

  setComponentState = (values) => {
    if (!this.state.isUnmounted) this.setState(values);
  };
}