reactive-robot-logo
reactive-robot

Simple

If you want simple, easy-to-use, battle-tested react state management, you have come to the right place. In concept, reactive-robot is a pub/sub observable system and event stream. It is a reactive system using an event driven architecture. It is simple and small, having been whittled down and refined over the years to the bare necessities. Not bear necessities, but really the lowest level bare necessities you actually need for state management.

Observer

reactive-robot is based on the observer pattern. An observer (or subscriber) subscribes to an observable (or publisher). When the observable changes, it notifies the observer. The observer can then react to the change, or not. If the observer is a react component, it can choose to re-render or not, based on the event it receives. This can radically simplify your react state management and improve rendering performance. In reactive-robot, anything can be a publisher or consumer of events. You are in complete control. There is nothing hidden and no magic.

Stream

With reactive-robot, you have an event stream. Very similar to rxjs. The original implementation was based on rxjs. But rxjs was unnecessary as there is no core need for modifying or filtering the event stream. This made reactive-robot much simpler. Call next(newEventName) to emit an event. Observers with a registered onEvent method will receive this event and can decide what they want to do about newEventName. If a store was updated and this component is pointing at data from that store, it can rerender. How? Fake A State Change

Fake State

With reactive-robot, there is no no automatic rerendering when data changes. That is the whole point. Change some data, and send an event. When an observer receives that event, and the event indicates the component should rerender, what do you do? You could update a value in the local component state that is then being displayed. But often you do not really need this, as you are only looking at data in a store. This is where you can use the convention of const [update, setUpdate] = useState(Date.now()). You can add update to a rendered DOM element as a data attribute. When you want to rerender, you call setUpdate(Date.now()). The component will rerender. This is a fake state update. You are not really updating any meaningful state in the component. You are just telling the component to rerender because you know that the data it cares about has been updated. This also provides a mechanism for performance testing, as your DOM element will display the exact time it was last rendered.

History

reactive-robot has had these major versions over the years:

  • 1.0 - react class components and rxjs event streams, extreme decoupling
  • 2.0 - react functional components with optional global state, no rxjs, boilerplate reduction
  • 3.0 - typescript or javascript, standard nomenclature, use any to allow for any data type
  • 4.0 - full type safety - store(s) defined by user, events are string only with no payload
  • 5.0 - payloads reimplemented with full type safety

Get Started

reactive-robot exposes an addObserver method. In your component where you want to receive events, make an onEvent method that takes a string as an argument and an optional data payload. Add that method to reactive-robot with a unique key representing the component, like rr.addObserver(myComponentNameString, onEvent). Your onEvent method should switch on the event name string so it can select the events of interest from the event stream. When an event is emitted with rr.next(eventNameString, data), your onEvent method will be called with that eventNameString and the recipient gets access to whatever is included in the data payload. Sending a data payload is completely optional. You can always put any data on the store object and any event recipient can use that directly. But there are times when data is not really global, but must be shared between two or more components. A data payload is useful in this case. You decide what to do when an event occurs. You can update your component state, re-render some data in the store, process some data, send another event, whatever. A useful pattern is to have display elements directly referring to values in the store. When the store is updated, the display elements are not automatically re-rendered. You do that. Send an event that lets the component know it needs to re-render. Use the convention of a fake state update to tell your component to rerender. You will never again have to worry about updates to your data causing unnecessary re-renders.

Thinking About State

When working with frontend react code, there are various types of state that you need to manage.

  • Local state - state that is only used within a single component
  • Global state - state that is shared between multiple components
  • Server sync - state that needs to by synced between server and client

Local state, within a single component, is usually best managed with the react useState hook. You could use reactive-robot for that, but it is not necessary. Global state, shared between multiple components, can be handled very efficiently with reactive-robot. Server sync is not something reactive-robot deals with directly. If you were using a library like react-query to sync client with server, you could use reactive-robot to manage complex client-side state changes that need to be reflected in the UI.