无法在未安装的组件上设置状态

时间:2018-08-16 12:30:39

标签: javascript reactjs asynchronous

我遇到了一个问题,希望有人可以帮助解释出现此错误的原因。当componentDidMount设置为componentWillUnmount时,我始终将isMounted设置为true和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(“崩溃前”,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仍在联接室组件中运行,这就是为什么一旦进入等候室组件就会失败吗?这基本上仅在从加入房间按钮触发createUser后才会出现

也感谢您的所有帮助。

1 个答案:

答案 0 :(得分:0)

您应先停止订阅事件,然后再卸载:

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

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

相关问题