无法在未安装的组件上调用 setState(或 forceUpdate)。这是一个空操作,但它表明您的应用程序中存在内存泄漏

IT技术 javascript reactjs firebase
2021-05-25 03:06:49

为什么我收到这个错误?

警告:无法在未安装的组件上调用 setState(或 forceUpdate)。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要修复,请取消 componentWillUnmount 方法中的所有订阅和异步任务。

postAction.js

export const getPosts = () => db.ref('posts').once('value');

组件:

constructor(props) {
  super(props);
  this.state = { posts: null };
}

componentDidMount() {
  getPosts()
    .then(snapshot => {
      const result = snapshot.val();
      this.setState(() => ({ posts: result }));
    })
    .catch(error => {
      console.error(error);
    });
}

componentWillUnmount() {
  this.setState({ posts: null });
}

render() {
  return (
    <div>
      <PostList posts={this.state.posts} />
    </div>
  );
}
4个回答

正如其他人提到的, componentWillUnmount 中的 setState 是不必要的,但它不应该导致您看到的错误。相反,可能的罪魁祸首是这段代码:

componentDidMount() {
  getPosts()
    .then(snapshot => {
      const result = snapshot.val();
      this.setState(() => ({ posts: result }));
    })
    .catch(error => {
      console.error(error);
    });
}

由于 getPosts() 是异步的,因此可能在解析之前,组件已卸载。您没有检查这一点,因此 .then 可以在组件卸载后最终运行。

为了解决这个问题,您可以在 willUnmount 中设置一个标志,并在 .then 中检查该标志:

componentDidMount() {
  getPosts()
    .then(snapshot => {
      if (this.isUnmounted) {
        return;
      }
      const result = snapshot.val();
      this.setState(() => ({ posts: result }));
    })
    .catch(error => {
      console.error(error);
    });
}

componentWillUnmount() {
  this.isUnmounted = true;
}

React 组件的状态是一个本地实体。卸载的组件没有状态,不需要这样做。React 已经告诉你这是一个no-op在技​​术上没有操作的意思。这意味着你告诉组件在它已经被销毁时做一些事情。

https://reactjs.org/docs/react-component.html#componentwillunmount

你不应该在 componentWillUnmount() 中调用 setState() 因为组件永远不会被重新渲染。一旦一个组件实例被卸载,它就永远不会再被装载。

删除这个

componentWillUnmount() {
  this.setState({ posts: null });
}

这毫无用处

从文档:

你不应该在 componentWillUnmount() 中调用 setState() 因为组件永远不会被重新渲染。一旦一个组件实例被卸载,它就永远不会再被装载。

https://reactjs.org/docs/react-component.html#componentwillunmount

你可以试试这个代码:

constructor(props) {
  super(props);
  this.state = { posts: null };
}

_isMounted = false;
componentDidMount() {
  this._isMounted = true;
  getPosts()
    .then(snapshot => {
      const result = snapshot.val();
      if(this._isMounted) { 
          this.setState(() => ({ posts: result }))
      }
    })
    .catch(error => {
      console.error(error);
    });
}

componentWillUnmount() {
  this._isMounted = false;
  this.setState({ posts: null });
}

render() {
  return (
    <div>
      <PostList posts={this.state.posts} />
    </div>
  );
}

通过使用 _isMounted,仅当组件已安装时才会调用 setState。答案只是在设置状态之前检查组件是否已安装。