Search code examples
javascriptreactjssocket.iocomponentslifecycle

Why is the new list only showing after an input change in react?


After submitting a new message through 'send' to add to the list I want rendered, no list is updated on the client screen. However, once I do anything in the input box AFTER that point, the item is then shown. So it's working...just not updating until after the modifier change call and not working how I want it to. :D

I think this is because hitting anything in the input afterward is updating the page, so the componentDidUpdate is called, but I'm unsure of why renderChatList isn't updating when I prefer it to.

What can I do or move around to fix that?

export class Chat extends React.Component{

  constructor(props){
    super(props);
    this.state = {
      text: '',
      nextId: 0,
      chatList: []
    };
  }

  componentDidMount(){
    socket.on('newMessage', (message) => {this.state.chatList.push({...message}) });
  }

  onTextChange(e){
    this.setState({text: e.target.value});
  }

  renderChatList() {
    return this.state.chatList.map((chatItem) => {
      return <li key={chatItem.createdAt}>{chatItem.from}: {chatItem.text}</li>
    });
  } 
  send(e) {
    e.preventDefault();
    socket.emit('createMessage', {
        from: this.props.owner,
        text: this.state.text
    }, function(){});
  }

  render(){
      return (
        <div>
          <form onSubmit={this.send.bind(this)}>
            <input type="text" onChange={this.onTextChange.bind(this)} placeholder="message"/>
            <button>Send chat</button>
          </form>
          <ul>{this.renderChatList()}</ul>
        </div>
      )
  }
};

Solution

  • Only by changing the state with setState() can the component rerender. You need to change the way you add a comment to the state to something like:

    socket.on('newMessage', (message) => {
      this.setState({ chatList: [...this.state.chatList, {...message}] }) 
    });
    

    The reason why the messages currently show after you type in some input is because changing the input changes the state with setState() and causes the component to rerender.