React this.setState() Issues

I am working on a game that sends backend server objects to frontend clients and then displays the data and then sends back user input back to the server. I am having trouble because when I call openRightGui and run this.setState() from my React Game class, it makes it so other calls to this.setState() error. Can someone please tell me my stupid error : )

Here is my react game element:

import './game.css';
import React from 'react';
import socket from 'socket.io-client';

import game_grid from './grid_image.jpg';

// Import Enemies

import Frie from './Enemies/Frie.js';

function centerX(grid_x){
  return (((grid_x-10)*-1) * 5).toString() + "%";
}

function centerY(grid_y){
  return (((grid_y-10)*-1) * 5 * 1.6).toString() + "%";
}

function getEnemy(enemy){
  switch(enemy.type){
    case 'Frie':
      return (<Frie x={enemy.x} y={enemy.y}/>)
    default:
      return '';
  }
}

class Game extends React.Component {
  constructor(props){
    super(props);

    let websocket;

    if (window.location.href.slice(0, 10) === 'http://loc'){
        websocket = socket("http://localhost:2999");
    } else {
        websocket = socket("http://IPADDRESS:2999");
    }
    
    this.state = {
      game: null,
      socket: websocket,
      right_gui_open: false,
      player: {name:"Undefined", x:0, y:0},
      player_request: [],
    }
    
    let getGame = (gameFiles) => {
      this.setState({game: JSON.parse(gameFiles)});
      this.state.socket.emit("getGame", this.props.state.server_id, this.props.state.username, this.state.player_request);
    }

    this.state.socket.emit("getGame", this.props.state.server_id, this.props.state.username, this.state.player_request);
    this.state.socket.on("gameFiles", getGame);

    this.closeRightGui = this.closeRightGui.bind(this);
    this.openRightGui = this.openRightGui.bind(this);
  }
  closeRightGui(){
    this.setState({right_gui_open: false});
  }

/* Right Here is where it errors 
/////
/////
/////
////
/////*/

  openRightGui(){
    console.log(this.state); // correctly outputs state
    this.setState({right_gui_open: false}); // this line breaks all other calls
  }
  render(){
    if (this.state.game === null){
      return (<div>Not connected to Game yet</div>);
    } else {
      this.setState({player:this.state.game.players.filter(player => player.name === this.props.state.username)[0]});

      let player_gui_display = this.state.game.players.map((player, i) => {
        if (player.name !== this.state.player.name){
          return (
          <div class='player-gui-display' id={i}><div>{player.name}</div><div class='coin-shower'>Coins: {player.coins}</div></div>)
        } else {
          return '';
        }
      })
      let right_gui = (
        <div>
          <button class='lift' onClick={this.closeRightGui}>Close</button>
          <div class='server-show'>Server: {this.state.game.server_name}</div>
          <div class='player-gui'>
            Players
            {player_gui_display}
          </div>
        </div>)

      return (
        <div class='container'>
          <div class='game'>
            <div class='game-stuff' style={{"top": centerY(this.state.player.y), "left": centerX(this.state.player.x)}}>
              <img src={game_grid} alt='Game Background'/>
             {this.state.game.enemies.map(enemy => getEnemy(enemy))}
            </div>
            <div class='gui'>
              <div class='top-gui'>
                {this.state.player.x}
              </div>
              <div class='right-gui'>
                {this.state.right_gui_open ? right_gui : (<button class='lift' onClick={this.openRightGui}>Open</button>)}
              </div>
            </div>
          </div>
        </div>
      )
    }
  }
}

export default Game;

I appreciate any help people can give me.

What error did you get?

When I looked inside the browser console, I get this:
error_message
game.js:72 is the react component that I load into the App component.

Line 72 in game.js is this.setState({player:this.state.game.players.filter(player => player.name === this.props.state.username)[0]}); in the render().

I did some more testing and found that the issue was caused whenever I updated the local state so I found that if I did the non recommended this.state.right_gui_open = true.
This is not an ideal solution but I can’t find another way around the issue.

My guess is that the error is coming from making so many this.setState({game}) calls from my websocket that it kind of just falls apart. Thank you for looking into this @Jimbalin .

I’m curious about two things:
What gets logged when you console.log(this.state)?
And your code here is making that property false, not true

this.setState({right_gui_open: false});

but in your next post you mutate it to true

Yeah, definitely never do that.

I’m a little concerned about calling setState in your render. That will get run on every render. It’s been a while since I worked with class components and that was mostly before the big switch in lifecycle methods, but I think what you want there is getDerivedStateFromProps.

Also, you can simplify your render a little:

  render(){
    if (this.state.game === null){
      return (<div>Not connected to Game yet</div>);
    } else {
      this.setState({player:this.state.game.players.filter(player => player.name === this.props.state.username)[0]});

could be:

  render(){
    if (this.state.game === null){
      return (<div>Not connected to Game yet</div>);
    }

    this.setState({player:this.state.game.players.filter(player => player.name === this.props.state.username)[0]});

Since you are using return in the if branch, there is no need for an else. Now we aren’t nesting branches.

I’m also a tiny bit concerned that you have a props that is this.props.state - that seems like a recipe for a mistake. That variable should have a better name.

I’d suggest you use the development version of React and not production. That should give you better error messages.

Not sure how you are running it but when in development you shouldn’t be using the production build (which you are in the screenshot you posted).


Anyway, I’d imagine we need a repo or a working example.

Sorry, I was trying to redo the function and was testing on closeRightGui and that was why it was false. As for what I get when I log state, it is kind of hard to tell. My browser freezes when I get all the errors and I can’t open or expand the logged this.state to see what is inside.

You are right. I will try refactoring the this.setState({player:this.state.game.players.filter(player => player.name === this.props.state.username)[0]}); up to the websocket receive function where I receive the game where it makes more sense.

I do think I set up my project a little weirdly. I have an express server that I wanted to have with my react app, but the react app ran on its own server. The way I worked around this was to have npm run start command run the react projects npm run build and then the express would serve the index.html. It is very complicated and I probably should run them separately before putting them together.

I haven’t tried it but I think you can make a development build (just don’t use it for the final deployment obviously).