ferp-js
  • What is Ferp
  • Getting Started
    • Installing Ferp in Your Application
    • What Does Ferp Provide
  • Building Your First App
    • The Boilerplate
  • Understanding Effects in Ferp
    • What is a Ferp Effect?
    • Core Effects
    • Composing Custom Effects
    • Testing Your Effects
  • Understanding Actions in Ferp
    • What is a Ferp Action?
    • Writing Your Own Actions
    • Testing Actions
  • Understanding Subscriptions in Ferp
    • What is a Ferp Subscription?
    • Composing Custom Subscriptions
    • Testing Your Subscriptions
  • Advanced Usage
    • Third-Party Libraries and Objects
Powered by GitBook
On this page
  • Handling Uncontrolled Third Party Objects
  • Rebuild objects by storing builder values
  • Event-driven objects

Was this helpful?

  1. Advanced Usage

Third-Party Libraries and Objects

Handling Uncontrolled Third Party 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.

Rebuild objects by storing builder values

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)

Event-driven objects

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,
    ],
  ],
});
PreviousTesting Your Subscriptions

Last updated 3 years ago

Was this helpful?