Third-Party Libraries and Objects
Not everything in the world is functional and immutable, and occasionally your application needs to manage these things. Ferp provides effects and subscriptions for handling these types of systems, but it's not always obvious which one to use and how to implement it.
In the example of firebase, you may have a document reference that is constructed by:
firebase.database(app).ref().collection('foo').document('bar')
While you could store the firebase ref object in state, having a serializable
effects/firebase.js
export const firebaseReadFx = (path, afterReadAction) => effects.defer((resolve) => {
firebase.database(app).ref(path).snapshot((value) => {
resolve(effects.act(afterReadAction, value));
});
});
// usage: firebaseReadFx('foo/bar', actionThatAcceptsValue)
If you have objects like websockets, those are perfect for subscriptions. Here's how I would set it up:
import { app, effects } from 'ferp';
const INITIAL_STATE = {
websocket_url: 'wss://echo.websocket.org',
websocket: null,
messages: [],
};
const WebsocketSendFx = (data, websocket) => effects.thunk(() => {
if (websocket) websocket.send(data);
return effects.none();
});
const WebsocketSend = data => state => [
state,
WebsocketSendFx(data, state.websocket),
];
const OnConnected = (websocket) => (state) => [
{ ...state, websocket },
effects.act(WebsocketSend, 'hello, world'),
];
const OnDisconnected = (state) => [
{ ...state, websocket: null },
effects.none(),
];
const OnMessage = (message) => (state) => [
{ ...state, messages: state.messages.concat(message) },
effects.none(),
};
const WebsocketSubscription = (dispatch, websocketUrl, ConnectAction, DisconnectAction, MessageAction) => {
const websocket = new WebSocket(websocketUrl);
const onOpen = () => dispatch(ConnectAction(websocket));
const onClose = () => dispatch(Disconnect);
const onMessage = ({ data }) => dispatch(MessageAction(data));
websocket.addEventListener('open', onOpen);
websocket.addEventListener('close', onClose);
websocket.addEventListener('message', onMessage);
return () => {
websocket.removeEventListener('open', onOpen);
websocket.removeEventListener('close', onClose);
websocket.removeEventListener('message', onMessage);
websocket.close();
};
};
const dispatch = app({
init: [INITIAL_STATE, effects.none()],
subscribe: state => [
state.websocketUrl && [
WebsocketSubscription,
state.websocketUrl,
OnConnect,
OnDisconnect,
OnMessage,
],
],
});
Last modified 1yr ago