【问题标题】:React Socket.io: Can only update a mounted or mounting componentReact Socket.io:只能更新已安装或正在安装的组件
【发布时间】:2017-05-05 03:23:40
【问题描述】:

我不断收到警告

警告:setState(...):只能更新已安装或已安装的组件。这通常意味着您在未安装的组件上调用了 setState()。这是一个无操作。请检查 RoundView 组件的代码。

它指向一个 socket.io 行

socket.on(
      'rankings',
      (payload) => this.setState({
        totals: payload.totals,
        scores: payload.scores
      },this.updateRoundProgress)
    );

但是该组件显然已安装并且一切似乎都运行良好,当捕获“排名”事件时,状态会更新得很好。完整代码如下:

https://github.com/JellyKid/ballsavr/blob/master/Frontend/app/components/user/RoundView.jsx

import React from 'react';
import handleFetch from '../../helpers/handleFetch';
import { Grid, Col, PageHeader } from 'react-bootstrap';
import { connect } from 'react-redux';
import update from 'immutability-helper';

import ConfirmScores from './view/ConfirmScores';
import Rankings from './view/Rankings';
import Scores from './view/Scores';
import Group from './view/Group';
import Manage from './view/Manage';

const socket = require('socket.io-client')('/round',{
  path: '/api/socket.io',
  autoConnect: false
});

class RoundView extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      round: this.props.round || {
        event: {
          title: 'Loading...'
        },
        name: "Please wait",
        tables: [],
        players: []
      },
      scores: [],
      totals: []
    };

    this.refreshScores = this.refreshScores.bind(this);
    this.updateRoundProgress = this.updateRoundProgress.bind(this);
  }

  componentDidMount(){
    this.handleSocket();
    let fetches = [
      handleFetch('GET',`/api/score/totals?round=${this.props.params.roundID}`),
      handleFetch('GET',`/api/score/round?id=${this.props.params.roundID}`)
    ];
    if(!this.props.round){
      fetches.push(handleFetch('GET', `/api/round/${this.props.params.roundID}`));
    }
    return Promise.all(fetches)
    .then(
      (res) => {
        this.setState({
          totals: res[0].payload,
          scores: res[1].payload,
          round: this.props.round || res[2].payload
        });
      }
    ).catch((err) => {console.log(err);});
  }

  handleSocket(){
    socket.open();
    socket.on(
      'connect',
      () => socket.emit('join round', this.props.params.roundID)
    );
    socket.on(
      'rankings',
      (payload) => this.setState({
        totals: payload.totals,
        scores: payload.scores
      },this.updateRoundProgress)
    );
    socket.on(
      'connect_error',
      () => setTimeout(socket.open, 1000)
    );
  }

  updateRoundProgress(){
    if(this.props.player.admin){
      let scores = this.state.scores.filter((score) => score.confirmed).length;
      let progress = Math.floor((scores/(this.state.round.tables.length * this.state.round.players.length))*100);
      return this.setState(update(
        this.state,
        {round: {progress : {$set: progress}}}
      ));
    }
  }

  refreshScores(){
    handleFetch('GET',`/api/score/round?id=${this.props.params.roundID}`)
    .then(
      (res) => this.setState({scores: res.payload})
    ).catch((err) => {console.log(err);});
  }

  componentWillUnmount(){
    socket.close();
  }

  render(){
    let player = this.state.round.players.find((p) => p.user._id === this.props.player._id);
    let groupName = (player) ? player.group : "";

    return (
      <Grid>
        <Col md={6} mdOffset={3}>
          <PageHeader>
            {this.state.round.event.title}<br/><small>{this.state.round.name}</small>
          </PageHeader>
          <Rankings
            totals={this.state.totals}
            players={this.state.round.players}
            player={this.props.player}
          />
          <hr />
          <Group
            group={groupName}
            players={this.state.round.players}
          />
          <hr />
          <Scores
            player={this.props.player}
            scores={this.state.scores}
            round={this.state.round}
            group={groupName}
          />
          <hr />
          <ConfirmScores
            scores={this.state.scores}
            player={this.props.player}
          />
          <hr />
          <Manage
            round={this.state.round}
            player={this.props.player}
          />
        </Col>
      </Grid>
    );
  }
}

function mapStateToProps(state, ownProps) {
  return {
    round: state.rounds.find((round) => round._id === ownProps.params.roundID),
    player: state.user
  };
}

export default connect(mapStateToProps)(RoundView);

当组件卸载时,我关闭了套接字。我还尝试在组件卸载时进行日志记录,并且在此之前它没有卸载,那么为什么我会收到错误消息?

【问题讨论】:

  • 你不断收到这个警告?
  • 这可能与您的组件也连接到 Redux 的事实有关,这意味着有另一个实例(未安装)正在侦听套接字。 - 我的猜测是尝试断开 redux 并查看是否有帮助。在任何情况下,我都会将套接字和可选的 redux 移动到容器组件中,这个组件上发生的事情太多了,无法轻松调试它!
  • 这就是问题所在。我将 socket.io 部分分成了它自己的组件。谢谢!

标签: reactjs socket.io


【解决方案1】:

这可能与您的组件连接到 Redux 的事实有关 同样,这意味着还有另一个实例(未安装) 监听套接字。 - 我的猜测是尝试断开 redux 和 看看是否有帮助。在任何情况下,我都会移动套接字,并且可以选择 redux 到一个容器组件,这有太多的事情发生了 组件来轻松调试它! ——帕特里克

谢谢帕特里克!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-13
    • 1970-01-01
    • 1970-01-01
    • 2017-03-02
    • 1970-01-01
    • 1970-01-01
    • 2017-04-26
    • 2017-05-29
    相关资源
    最近更新 更多