Cookbook Suggestion: Handling realtime events on the client side with redux-saga
devashishsethia opened this issue · comments
Comment/Problem
There are not many handy guides around how do you handle real-time events with redux-saga. I had to do a lot of work to get there. I think this can help anyone who is feeling lost.
Setup client (feathers.js)
import AsyncStorage from '@react-native-community/async-storage';
import feathers from '@feathersjs/feathers';
import socketio from '@feathersjs/socketio-client';
import io from 'socket.io-client';
import auth from '@feathersjs/authentication-client';
const socketOptions = {
transports: ['websocket'],
forceNew: true,
};
const authOptions = {
storage: AsyncStorage,
};
const socket = io('http://feathers-server-url', socketOptions);
const client = feathers();
client.configure(socketio(socket, {timeout: 15000}));
client.configure(auth(authOptions));
client.service('payments').timeout = 15000;
export default client;
Set up a watcherSaga
import {take, put, call} from 'redux-saga/effects';
import {eventChannel} from 'redux-saga';
import FeathersClient from '../../feathers';
import {addNewTxn} from 'redux/walletTransactions/actions';
//We're trying to listen for an event when a new transaction is added
// this function creates an event channel from a given socket
function createSocketChannel(feathersClient) {
// `eventChannel` takes a subscriber function
// the subscriber function takes an `emit` argument to put messages onto the channel
return eventChannel(emit => {
const walletTxnHandler = txnData => {
emit({type: 'walletTxn', txnData: txnData});
};
// setup the subscription
const walletService = feathersClient.service('wallet-transactions');
walletService.on('created', walletTxnHandler);
// the subscriber must return an unsubscribe function
// this will be invoked when the saga calls `channel.close` method
const unsubscribe = () => {
walletService.removeListener('created', walletTxnHandler);
};
return unsubscribe;
});
}
export function* listenForSocketEvents() {
const socketChannel = yield call(createSocketChannel, FeathersClient);
while (true) {
try {
// An error from socketChannel will cause the saga jump to the catch block
const socketEvent = yield take(socketChannel);
switch (socketEvent.type) {
case 'walletTxn':
yield put(addNewTxn(socketEvent.txnData)); //dispatch the action with the txnData
break;
}
} catch (err) {
console.error('socket error:', err);
}
}
}
I understand and agree that this is probably not feathers specific. So, please feel free to drop.