【问题标题】:can't setState on an unmounted component无法在未安装的组件上设置状态
【发布时间】:2018-08-16 12:30:38
【问题描述】:

我遇到了一个问题,我希望有人可以帮助解释这个错误出现的原因。当一个componentDidMount 我总是将isMounted 设置为true 和componentWillUnmount 时为false。现在我有点困惑,因为在所附的图像中,我把 console.logs 都放了一遍,看看什么在运行什么。在图片中,您可以看到该组件已安装但失败。Shows console.logs and error

当我打开错误时,有两个地方说它失败了。第一个是

 gameStarted() {
    let gameID = this.props.match.params.id;
    let db = firebase.database();
    db.ref(`Room/${gameID}`).on("value", snapshot => {
      let collection = snapshot.val();
      if (collection === null) {
        return;
      }
      if (
        collection["gameStarted"] === null ||
        collection["gameStarted"] === undefined
      ) {
        return;
      }
      let startGame = collection["gameStarted"];
      console.log("before crash");
      if (this.state.isMounted) {
        console.log("before crash", this.state.isMounted);
        this.setState(
          {
            startGame
          },
          () => {
            console.log("Start Game Worked");
          }
        );
      }
      console.log("after crash");
    });
  }

从上图中我们可以看到 console.log("before crash", true) 是在错误出现之前运行的。我在这方面有点困惑,因为它应该可以工作,因为本地状态设置为 true?不?

下一个出现的错误在不同的组件中。它的设置方式是,如果用户不属于等候室,他们将被重定向到加入房间组件。这是第二个错误出现的地方

   const loginPromise = new Promise((resolve, reject) => {
      firebase.auth().onAuthStateChanged(user => {
        if (user) {
          window.user = user;
          resolve(user.uid);
        } else {
          firebase
            .auth()
            .signInAnonymously()
            .then(user => {
              resolve(user.uid);
            })
            .catch(err => {
              console.log(err);
            });
        }
      });
    });
    loginPromise.then(id => {
      console.log("before crash", this.state.isMounted);
      let db = firebase.database();
      let playersRef = db.ref(`Room/${this.state.accesscode}/players`);
      playersRef.child(`${id}`).set(`${this.state.username}`);
      console.log("After crash", this.state.isMounted);
      let player = db.ref(`Room/${this.state.accesscode}/players/${id}`);
      player.onDisconnect().remove();

      let allPlayers = db.ref(`Room/${this.state.accesscode}/all-players`);
      allPlayers.child(`${id}`).set(true);
      let allPlayer = db.ref(`Room/${this.state.accesscode}/all-players/${id}`);
      allPlayer.onDisconnect().remove();

      let scoreBoard = db.ref(`Room/${this.state.accesscode}/scoreBoard`);
      scoreBoard.child(`${this.state.username}`).set(0);
      let playerScore = db.ref(
        `Room/${this.state.accesscode}/scoreBoard/${this.state.username}`
      );
      playerScore.onDisconnect().remove();

      this.props.history.push({
        pathname: `/waiting-room/${this.state.accesscode}`
      });
    });
  }

虽然我不认为这部分是这种情况,因为在控制台中它仍然会继续运行而不会崩溃。因此,当用户设置等候室 url 时,如果他们不是房间的一部分,他们将被重定向到加入房间组件,在返回游戏房间组件之前,他们需要输入用户名。我知道这些重定向可能是问题所在,关于如何解决这个关于卸载组件的 setState 的任何建议?

[更新] 可能是因为 promise 仍在 join-room 组件中运行,这就是为什么它在前往等候室组件时失败的原因?这基本上只在从加入房间按钮触发 createUser 时才会出现

也感谢大家的帮助。

【问题讨论】:

    标签: javascript reactjs asynchronous


    【解决方案1】:

    您应该在卸载前停止订阅事件:

    componentWillUnmount() {
        let gameID = this.props.match.params.id;
        let db = firebase.database();
        db.ref(`Room/${gameID}`).off("value");
    }
    

    您的组件将停止接收更新事件并且状态不会被更新

    【讨论】:

    • 谢谢。这解决了我遇到的问题并且很高兴学习新东西:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2021-11-05
    • 1970-01-01
    • 2020-09-04
    • 2020-08-03
    相关资源
    最近更新 更多