I'm using middleware in Redux to connect to my signalR hub, which works perfectly and I can receive messages no problem.
Now I have got to the point where I want to invoke a method on the server to "Join a Group".
What is the best way to do so? I have a connection, so recreating the connection on the action "JOIN_GROUP" seems counter intuitive.
I thought I might be onto something when I read xxx, so I could chain
import {
JsonHubProtocol,
HttpTransportType,
HubConnectionBuilder,
LogLevel,
} from '@microsoft/signalr';
import actionTypes from '../actions/actionTypes';
const startSignalRConnection = (connection) =>
connection
.start()
.then(() => console.info('SignalR Connected'))
.catch((err) => console.error('SignalR Connection Error: ', err));
const signalRMiddleware =
({ dispatch, getState }) =>
(next) =>
async (action) => {
let connection;
// register signalR after the user logged in
if (action.type === actionTypes.USER_SIGNED_IN) {
const connectionHub =
window.globalConfig?.hubUrl || process.env.REACT_APP_HUB_URL;
const protocol = new JsonHubProtocol();
// let transport to fall back to to LongPolling if it needs to
const transport =
HttpTransportType.WebSockets | HttpTransportType.LongPolling;
const options = {
transport,
logMessageContent: true,
logger: LogLevel.Critical,
accessTokenFactory: () => action.user.access_token,
};
// create the connection instance
connection = new HubConnectionBuilder()
.withUrl(`${connectionHub}/hub/notificationhub`, options)
.withHubProtocol(protocol)
.build();
//add "on" events here...
// re-establish the connection if connection dropped
connection.onclose(() =>
setTimeout(startSignalRConnection(connection), 5000)
);
startSignalRConnection(connection);
} else if (action.type === actionTypes.JOIN_GROUP) {
connection.invoke('JoinGroup', action.groupName);
}
return next(action);
};
export const joinGroup = (groupName) => (dispatch, getState, invoke) => {
invoke('JoinGroup', groupName);
};
export default signalRMiddleware;
When I dispatch the "JOIN_GROUP" action, the connection is undefined:
} else if (action.type === actionTypes.JOIN_GROUP) {
// connection is undefined
connection.invoke('JoinGroup', action.groupName);
}
I did read somewhere about being able to pass the invoke method from the connection onto another method. Hence:
export const joinGroup = (groupName) => (dispatch, getState, invoke) => {
invoke('JoinGroup', groupName);
};
But I have no idea how to use it, or populate the invoke in order to use it in my component.
Any help would be much appreciated.
Alex
Managed to work it out. In the end it was a very small tweak, in that the let connection needed to be before the initial (next)
import {
JsonHubProtocol,
HttpTransportType,
HubConnectionBuilder,
LogLevel,
} from '@microsoft/signalr';
import actionTypes from '../actions/actionTypes';
const startSignalRConnection = (connection) =>
connection
.start()
.then(() => console.info('SignalR Connected'))
.catch((err) => console.error('SignalR Connection Error: ', err));
const signalRMiddleware = ({ dispatch, getState }) => {
let connection;
return (next) => async (action) => {
// register signalR after the user logged in
if (action.type === actionTypes.USER_SIGNED_IN) {
const connectionHub =
window.globalConfig?.hubUrl || process.env.REACT_APP_HUB_URL;
const protocol = new JsonHubProtocol();
// let transport to fall back to to LongPolling if it needs to
const transport =
HttpTransportType.WebSockets | HttpTransportType.LongPolling;
const options = {
transport,
logMessageContent: true,
logger: LogLevel.Critical,
accessTokenFactory: () => action.user.access_token,
};
// create the connection instance
connection = new HubConnectionBuilder()
.withUrl(`${connectionHub}/hub/notificationhub`, options)
.withHubProtocol(protocol)
.build();
//add "on" events here...
// re-establish the connection if connection dropped
connection.onclose(() =>
setTimeout(startSignalRConnection(connection), 5000)
);
startSignalRConnection(connection);
} else if (action.type === actionTypes.JOIN_GROUP) {
connection.invoke('JoinGroup', action.groupName);
return;
}
return next(action);
};
};
export default signalRMiddleware;