PetSilv
PetSilv

Reputation: 33

How to properly render heavy web socket stream in React?

I currently have something like this:

const socket = require('socket.io-client')('https://example.com');
(....)

// Listen to the channel's messages
socket.on('m', message => {
    // this is a Redux action that updates the state
    this.props.updateTrades(message);
});

The reducer looks like this:

        case actions.UPDATE_TRADES:
        return {
            ...state,
            trades: [
                ...state.trades,
                action.trade
            ]
        };

I've tried not using redux and just to the following:

        socket.on('m', message => {
            this.setState(state => {
                if (state.trades.length > 99) {
                    state.trades.splice(0, 1);
                }
                return {
                    trades: [
                        ...state.trades,
                        message
                    ]
            });
        });

I don't need to keep increasing my trades array. I'm happy just to keep around 100 items or so...

Socket is sending around 15 messages / second. My problem is: I can't seem to render the messages in real-time! It just freezes. I guess the stream is just too fast? Any suggestions?

Thanks in advance!

Upvotes: 2

Views: 1674

Answers (2)

Guillermo Quiros
Guillermo Quiros

Reputation: 441

The thing is to do the minimum possible and when the trades change only draw what has change and not all of the elements of the array.A technique that I use is to keep a cache map of already drawn obj, so in the render method I only render the new incoming elements.

Take a look at https://codesandbox.io/s/wq2vq09pr7

class RealTimeList extends React.Component {
  constructor(props) {
    super(props);
    this.cache = [];
  }
  renderRow(message, key) {
    return <div key={key}>Mesage:{key}</div>;
  }
  renderMessages = () => {
    //let newMessages=this,props.newMessage
    let newElement = this.renderRow(this.props.message, this.cache.length);
    this.cache.push(newElement);
    return [...this.cache];
  };
  render() {
    return (
      <div>
        <div> Smart List</div>
        <div className="listcontainer">{this.renderMessages()}</div>
      </div>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: "hi" };
  }

  start = () => {
    if (this.interval) return;
    this.interval = setInterval(this.generateMessage, 200);
  };
  stop = () => {
    clearTimeout(this.interval);
    this.interval = null;
  };

  generateMessage = () => {
    var d = new Date();
    var n = d.getMilliseconds();
    this.setState({ title: n });
  };

  render() {
    return (
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
        <button onClick={this.start}> Start</button>
        <button onClick={this.stop}> Stop</button>
        <RealTimeList message={this.state.message} />
      </div>
    );
  }
}

The class RealTime List have a cache of elements.Let me know if this helps.

Upvotes: 1

Dakota
Dakota

Reputation: 1274

It's probably not a good idea to try to render all of the changes. I think you should try rendering them in batches so you only update once every few seconds, that should help.

Upvotes: 0

Related Questions