title: React Socket.io: Can only update a mounted or mounting component
body: <p>I'm getting repeated warnings </p>
  
  <p><strong><em>Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the RoundView component.</em></strong></p>
  
  <p>and it points to a socket.io line</p>
  
  <pre><code>socket.on(
        'rankings',
        (payload) =&gt; this.setState({
          totals: payload.totals,
          scores: payload.scores
        },this.updateRoundProgress)
      );
  </code></pre>
  
  <p>But the component is clearly mounted and everything seems to function fine, the state gets updated just fine when a 'rankings' event is captured. The full code is below:</p>
  
  <p><a href="https://github.com/JellyKid/ballsavr/blob/master/Frontend/app/components/user/RoundView.jsx" rel="nofollow noreferrer">https://github.com/JellyKid/ballsavr/blob/master/Frontend/app/components/user/RoundView.jsx</a></p>
  
  <pre><code>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) =&gt; {
          this.setState({
            totals: res[0].payload,
            scores: res[1].payload,
            round: this.props.round || res[2].payload
          });
        }
      ).catch((err) =&gt; {console.log(err);});
    }
  
    handleSocket(){
      socket.open();
      socket.on(
        'connect',
        () =&gt; socket.emit('join round', this.props.params.roundID)
      );
      socket.on(
        'rankings',
        (payload) =&gt; this.setState({
          totals: payload.totals,
          scores: payload.scores
        },this.updateRoundProgress)
      );
      socket.on(
        'connect_error',
        () =&gt; setTimeout(socket.open, 1000)
      );
    }
  
    updateRoundProgress(){
      if(this.props.player.admin){
        let scores = this.state.scores.filter((score) =&gt; 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) =&gt; this.setState({scores: res.payload})
      ).catch((err) =&gt; {console.log(err);});
    }
  
    componentWillUnmount(){
      socket.close();
    }
  
    render(){
      let player = this.state.round.players.find((p) =&gt; p.user._id === this.props.player._id);
      let groupName = (player) ? player.group : "";
  
      return (
        &lt;Grid&gt;
          &lt;Col md={6} mdOffset={3}&gt;
            &lt;PageHeader&gt;
              {this.state.round.event.title}&lt;br/&gt;&lt;small&gt;{this.state.round.name}&lt;/small&gt;
            &lt;/PageHeader&gt;
            &lt;Rankings
              totals={this.state.totals}
              players={this.state.round.players}
              player={this.props.player}
            /&gt;
            &lt;hr /&gt;
            &lt;Group
              group={groupName}
              players={this.state.round.players}
            /&gt;
            &lt;hr /&gt;
            &lt;Scores
              player={this.props.player}
              scores={this.state.scores}
              round={this.state.round}
              group={groupName}
            /&gt;
            &lt;hr /&gt;
            &lt;ConfirmScores
              scores={this.state.scores}
              player={this.props.player}
            /&gt;
            &lt;hr /&gt;
            &lt;Manage
              round={this.state.round}
              player={this.props.player}
            /&gt;
          &lt;/Col&gt;
        &lt;/Grid&gt;
      );
    }
  }
  
  function mapStateToProps(state, ownProps) {
    return {
      round: state.rounds.find((round) =&gt; round._id === ownProps.params.roundID),
      player: state.user
    };
  }
  
  export default connect(mapStateToProps)(RoundView);
  </code></pre>
  
  <p>I close the socket when the component unmounts. I also tried logging when the component unmounts and it doesn't unmount before this so why the heck am I getting the error?</p>