'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", "&")
.replace("/</g", "<")
.replace("/>/g", ">");
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 |