# 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:

```javascript
firebase.database(app).ref().collection('foo').document('bar')
```

While you could store the firebase ref object in state, having a serializable

{% code title="effects/firebase.js" %}

```javascript
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)
```

{% endcode %}

### Event-driven objects

If you have objects like websockets, those are perfect for subscriptions. Here's how I would set it up:

```javascript
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,
    ],
  ],
});
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ferp.mrbarry.com/advanced-usage/third-party-libraries-and-objects.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
