-
-
Save markerikson/3df1cf5abbac57820a20059287b4be58 to your computer and use it in GitHub Desktop.
const createMySocketMiddleware = (url) => { | |
return storeAPI => { | |
let socket = createMyWebsocket(url); | |
socket.on("message", (message) => { | |
storeAPI.dispatch({ | |
type : "SOCKET_MESSAGE_RECEIVED", | |
payload : message | |
}); | |
}); | |
return next => action => { | |
if(action.type == "SEND_WEBSOCKET_MESSAGE") { | |
socket.send(action.payload); | |
return; | |
} | |
return next(action); | |
} | |
} | |
} | |
// later, in your app | |
function sendSocketMessage(message) { | |
return { | |
type : "SEND_WEBSOCKET_MESSAGE", | |
payload : message | |
} | |
} | |
class MyComponent extends React.Component { | |
handleClick = () => { | |
this.props.sendSocketMessage("This goes to the server"); | |
} | |
} | |
export default connect(null, {sendSocketMessage})(MyComponent) |
@markerikson: Thank you for your response Mark. Well, I've used your example here and on Stackoverflow as a base to configure the Socket middleware
with Socket IO
and Laravel Echo
in this way and just as the docs recommends I use .concat
to append the middleware to the store:
(Each section is in its own file)
// Actions
// Get data
export const getData = createAction('socket/getData', data => {
return {
payload: {
data,
id: nanoid(),
createdAt: new Date().toISOString(),
},
};
});
// Send data
export const sendData = createAction('socket/sendData', data => {
return {
payload: {
data,
id: nanoid(),
createdAt: new Date().toISOString(),
},
};
});
// Disconnect
export const disconnect = createAction('socket/disconnect');
// Socket middleware
export const createSocketMiddleware = url => {
let socket;
let echo;
return storeAPI => next => action => {
switch (action.type) {
// Connect after user is authenticated
case 'user/login/fulfilled': {
socket = socketIOClient(`${url}:3010/socket`);
// Create a new Echo class instance
echo = new Echo({
host: `${url}:6001`,
broadcaster: 'socket.io',
client: socketIOClient,
auth: {
headers: {
Authorization: axios.defaults.headers['Authorization'],
},
},
});
// Connect and listen
echo.private('transport.1').listen('.order-pending', ev => {
storeAPI.dispatch(getData(ev));
});
break;
}
// Send data
case 'socket/sendData': {
socket.emit('order-pending', action.payload);
break;
}
// Disconnect
case 'socket/disconnect': {
echo.disconnect();
break;
}
}
return next(action);
};
};
// Reducer
const socketReducer = createReducer(initialState, builder => {
builder
.addCase(getData, (state, action) => {
state.data = action.payload.data;
})
.addCase(disconnect, (state, action) => {
return initialState;
});
});
// Store
export const store = configureStore({
reducer: persistedReducer,
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}).concat(createSocketMiddleware(url)),
devTools: process.env.NODE_ENV === 'development' && true,
});
Everything is working as expected yet I myself am a bit cautious regarding this method due to the lack of adequate examples and am wondering if it indeed adheres to the Redux standards.
One more question I was wondering about is why is redux requiring the WebSocket connection to be as a middleware and how is RTK Query handling this issue with its Streaming Updates that plain Redux Toolkit is unable to do.
@n-ii-ma looks fine at first glance.
You might want to look at the FAQ entry that describes why we normally recommend that websocket-type connections should go into a middleware:
@markerikson Many thanks Mike!
Upon further consideration and after a conversation with Lenz, I decided to use the listenerMiddleware
, yet I'm still trying to figure out how to stop a particular listener
@n-ii-ma probably best to ask over in #redux
in Reactiflux, but typically you'd dispatch an action and have the listener do an await take(thatAction)
and then cancel itself / return.
@n-ii-ma : not sure I understand the question.
Setup-wise this would be added to the
middleware
option inconfigureStore
as usual.Can you clarify what you're asking?