Tristan
Tristan

Reputation: 2088

React app gets slow renders slow after emitting socketio message

I have a react app. The code does work perfectly but after using it. It starts getting slow. After waiting for a while you can use it again.

When you press a button, I use socketio to emit a message.

Function call takes longer after using it multiple times.

The function call is part of websocket.js. However when you dig deeper in the functions it seems like react rendering is taking longer.

Function that is taking a lot of time.

So react takes a lot of time to render the view. I can only think then that I don't delete something which will use a lot of memory and thus slow down the rendering process. On the picture you see that it is in the file react-dom.development.js, the issue also occurs when it is build for production.

import React, { Component } from 'react';
import Card from './Card.js'

class Game extends Component {
  constructor(props) {
    super(props);
    this.state = {
      socket: this.props.socket,
      card: {
        "name": "",
        "cardValues": {}
      }
    }
    this.props.socket.emit("startGame");
  }
  render() {
    let {socket, card} = this.state;
    socket.on("startGame", (data) => this.setState({
        card: data["card"],
    }))
    socket.on("nextCard", (data) => this.setState({
        card: data["nextCard"],
    }))
    return (
      <div className="Game">
          <p>GAME</p>
          <Card socket={socket} card={this.state.card}/>
      </div>
    );
  }
}
export default Game;

This part uses the class Card.

import React, { Component } from 'react';

class Card extends Component {
  constructor(props) {
    super(props);
    this.state = {
      socket: this.props.socket,
    }
  }

  chooseCardValue = (value) => {
      this.state.socket.emit("chooseCard", {"cardValue": value});
  }

  render() {
    let card = this.props.card;
    return (
      <div className="Card">
          <h3 className="Country">{card["name"]}</h3>
          <ul>
            {
              Object.keys(card["cardValues"]).map((value, i) => {
                return <li key={i}><button onClick = {
                    this.chooseCardValue.bind(null, value)
                }>{value}: {card["cardValues"][value]}</button></li>
              })
            }
          </ul>
      </div>
    );
  }
}
export default Card;

It is here where the buttons are defined. When you click the button it triggers the function chooseCardValue which becomes slow after time.

Why does it become so slow, and what is the cause?

I tried to only include the parts that could be relevant. The whole classes are available here just in case: https://lpaste.net/3474101090415280128

Upvotes: 4

Views: 2367

Answers (1)

david
david

Reputation: 18258

You are attaching your socket listeners inside the render method. This means that every time your app re-renders you will add 2 extra listeners. Additionally, inside the listeners you call setState, which triggers a re-render, which adds another listener.

The first time you get a message your app will render once, and add a listener. The second time you get a message your app will render twice (once for each listener) and you will add 2 listeners. The third time there will be 4 renders. Then 8, 16, 32 and so on.

Essentially what you need to do is not add those listeners in the render method. You could try moving them to the constructor or the componentDidMount method, but really it should be somewhere external to the component tree.

For clarity these are the lines that I'm talking about:

let {socket, card} = this.state;
socket.on("startGame", (data) => this.setState({
    card: data["card"],
}))
socket.on("nextCard", (data) => this.setState({
    card: data["nextCard"],
}))

Upvotes: 2

Related Questions