Redux Saga with WebSocket
import { eventChannel, END } from 'redux-saga';
import { call, put, take, fork, cancel, cancelled } from 'redux-saga/effects';
import * as LiveDataActions from '../../redux/LiveData/LiveData.actions';
import * as LiveDataTypes from '../../redux/LiveData/LiveData.types';
// Use this to actually throw exceptions, allows for easier debugging.
const dispatch = put.resolve;
function createWebSocketConnection() {
return new Promise((resolve, reject) => {
const socket = new WebSocket("ws://localhost:1555");
socket.onopen = function () {
resolve(socket);
};
socket.onerror = function (evt) {
reject(evt);
}
});
}
function createSocketChannel(socket) {
return eventChannel(emit => {
socket.onmessage = (event) => {
emit(event.data)
};
socket.onclose = () => {
emit(END);
};
const unsubscribe = () => {
socket.onmessage = null;
};
return unsubscribe;
});
}
function* listenForSocketMessages() {
let socket;
let socketChannel;
try {
socket = yield call(createWebSocketConnection);
socketChannel = yield call(createSocketChannel, socket);
// tell the application that we have a connection
yield dispatch(LiveDataActions.connectionSuccess());
while (true) {
// wait for a message from the channel
const payload = yield take(socketChannel);
// a message has been received, dispatch an action with the message payload
yield dispatch(LiveDataActions.incomingEvent(payload));
}
} catch (error) {
yield dispatch(LiveDataActions.connectionError('Error while connecting to the WebSocket'));
} finally {
if (yield cancelled()) {
// close the channel
socketChannel.close();
// close the WebSocket connection
socket.close();
} else {
yield dispatch(LiveDataActions.connectionError('WebSocket disconnected'));
}
}
}
export function* connect() {
// starts the task in the background
const socketTask = yield fork(listenForSocketMessages);
// when DISCONNECT action is dispatched, we cancel the socket task
yield take(LiveDataTypes.DISCONNECT);
yield cancel(socketTask);
yield dispatch(LiveDataActions.disconnectSuccess());
}