How to handle SignalR reconnection logic in React without triggering useEffect on every state change?
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 276
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Is your feature request related to a problem? Please describe the problem.
Hi, I have this case in my SPA:
I'm using SignalR in my project to receive some data from the backend. In the root of the project, example App.tsx, I create the connection to the Hub and store the connection in zustand store, to access the connection throughout the app.
Now, I have some component where I connect my users to "rooms" in the Hub connection. The user needs to select the Room (or rooms, they could join 1 or more), and I invoke the function in my hub to connect the user.
```ts
component A = (): JSX.Element => {
const connection = useHubConnectionStore(state => state.connection);
const [roomsSelected, setRoomsSelected] = useState([]);
const handleSelect = (check: boolean, roomId: number) => {
try{
const res = await connection?.invoke("ConectarUsuarioSucursalRoom", roomId);
var newRoomsValue = check ?
[...roomsSelected, roomId]
: roomsSelected.filter((id) => id !== roomId);
setRoomsSelected(newRoomsValue);
}catch(e){
// show error
}
}
```
This works perfect. So ok, now the problem is that, I want to `reconnect` the users to the rooms from the client, in case the connection has been lost. The SignalR library has a handler for know when the connection was reconnected:
`.onreconnected()`
So I thought the correct way is, put that in useEffect:
```ts
component A = (): JSX.Element => {
const connection = useHubConnectionStore(state => state.connection);
const [roomsSelected, setRoomsSelected] = useState([]);
useEffect(() => {
connection.onreconnected(async connectionId => {
// iterate each roomSelected and .invoke again
});
return () => {//clean up handler, what is fun cause signalR has not implemented yet the offreconnected method}
}, [connection, roomsSelected]);
const handleSelect = (check: boolean, roomId: number) => {
try{
const res = await connection?.invoke("ConectarUsuarioSucursalRoom", roomId);
var newRoomsValue = check ?
[...roomsSelected, roomId]
: roomsSelected.filter((id) => id !== roomId);
setRoomsSelected(newRoomsValue);
}catch(e){
// show error
}
}
```
But obviously, the problem is that SignalR doesn't have the method to clean the handler, and in every `setRoomsSelected` a new handler is registered. So the first thing I thought, was register the `.onreconnected()` method in the `App.tsx` (globally) where I create the connection, and for example, create new prop in the `useHubConnectionStore` called `isReconnected` or `isConnected`, but the things start to get complicated, and I'm not sure what's the best way to solve this without the method to clean the handler.
### Describe the solution you'd like
A tip on how to solve it
### Additional context
I already "solved" with the global `onreconnected` in `App.tsx`, storing the rooms for that component in the zustand store, but I don't like it cause now the `.onreconnected()` global handler, has specific logic for this component, imagine in future if I need do other stuff in other screens when the connection was reconnected.
Contributor guide
Assessment
This issue has not been assessed yet.