'SignalR with React not very Realtime

I followed this this tutorial for signalR with vanilla javascript and all went well. I opened two browsers and both get updated instantly once I send a message from any of them. PROBLEM is located at the bottom.

Then I started another project in VS2017, this time a React template using aspnet core 2.1. Added signalr in Startup.cs

services.AddMvc().SetCompa.....
services.AddSignalR(); // added this
services.AddSpaStaticFiles......

app.UseSpaStaticFiles();
// then added below code
app.UseSignalR(routes =>
{
    routes.MapHub<ChatHub>("/chathub");
});
app.UseMvc(.....

Used this chathub class

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

and tried to convert the vanilla JS code to this react one

....
this.state = { name: "", message: "", messages: [], hubConnection: null }
...
componentDidMount() {
    const connection = new SignalR.HubConnectionBuilder()
        .withUrl("/chathub")
        .build();
    connection.on("ReceiveMessage", (user, message) => this.receiveMessage(user, message))
    connection.start().catch(err => console.error(err.toString())); 
    this.setState({ hubConnection: connection });
}

receiveMessage = (user, message) => {
    let msgs = this.state.messages;
    const msg = message
      .replace("/&/g", "&amp;")
      .replace("/</g", "&lt;")
      .replace("/>/g", "&gt;");
    const encodedMsg = user + " says " + msg;
    msgs.push(encodedMsg);
}

sendMessage = async (event) => {
    event.preventDefault();
    let user = this.state.name;
    let message = this.state.message;
    let connection = this.state.hubConnection;
    await connection
      .invoke("SendMessage", user, message)
      .catch(err => console.error(err.toString()));
    this.setState({ name: "", message: "" });
}; 

then added the following in render

<p>User: </p><input type="text" id="userInput" value={this.state.name} onChange={event => { this.setState({ name: event.target.value }); }} />
<p>Message: </p><input type="text" id="messageInput" value={this.state.message} onChange={event => { this.setState({ message: event.target.value }); }} />
<input type="button" id="sendButton" onClick={this.sendMessage} value="Send Message"/>

<ul>
    {this.state.messages.map(message => (
        <li key={message}>{message.toString()}</li>
    ))}
</ul>

then bound the methods to the class. Issue, other browser does not update instantly when the other browser send message. I need to perform some action which will cause it to rerender, like typing something in the input field. So how do I make it listen to incoming messages and rerender when it receive one? The problem which i think I have is that my client code does not know how to listen to the messages unless it's the one who called explicitly the SendMessage method



Solution 1:[1]

A bit shorter:

setState(prevState => ({
    ...prevState,
    messages: [...prevState.messages, newMessage]
}));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1