This video is available to students only

Introduction to State Management

Reframe is a flux-like library for uni-directional data flow. In this chapter we'll study the six-step Reframe loop.

Introduction to state management#

State management in React is a controversial issue. There are multiple competing models like MobX, React Context, and Flux.

In this chapter, we'll walk through the concepts and terminologies of two ways of managing the app state: Reframe and reactive atoms. The focus right now is to form a mental model, but in later chapters we'll realize the models.

We have already seen r/atom in action. Ratoms are a simple yet powerful way to store state. We can have one or more ratoms, and components that listen to them. But as your app grows, keeping track of these atoms get hard. Performance will suffer as we have little control over the re-render cycle. If anything in the ratom changes, all listener components will be re-rendered.


Reframe is a Redux-like framework with a uni-directional data loop. It allows you to structure application state and enables optimal rendering. First released in 2015, it is now one of the most starred Clojure projects.

The authors of Reframe explain it as a 6-step process. Let's walk through the steps with an example.

Imagine you have a form with two input components - email and password - and you want to re-render the form each time a user types something. The skeleton of the component might look something like this:

(This component won't work because the :value is fixed and :on-change is not implemented - just focus on the outline for now.)

Step 1 - Dispatching events#

The first step of the Reframe loop is to dispatch or emit an event. This event could be:

  • a keystroke in an input field

  • a click of a button

  • a message on a WebSocket

  • mouse motion

  • etc

In the example above, the user typing in the input field is the event we wish to capture.

To set the loop in motion, we use the reframe.core/dispatch method:

dispatch accepts a vector where the first element is the id of the event we want to dispatch. Data that we wish to pass along can be passed in the vector.

In more concrete terms, in the login-form component, we wish to save the state in Reframe. We can modify the :on-change handlers to dispatch change events:

We used inline functions to dispatch events each time the input changed. This is not the ideal approach but is easy to understand. Both (fn []) and #() have the same behavior - both call dispatch and set the Reframe loop in motion.

Step 2 - Event handlers#

For a dispatch to be useful, we need to handle the dispatched event. This can be done using reframe.core/reg-event-fx method (AKA register event effect method). reg-event-fx takes two arguments: the event id and a pure handler function. Event ids are keywords and generally namespaced. :handle-email-change and :handle-password-change are examples of events that change the state of the app.

This handler function is called with two arguments each time the event is dispatched.

The first argument is the co-effects map - you can think of this as the current state of the universe. The second argument is the vector we passed to dispatch:

This is a good time to disclose that Reframe keeps the entire application state in one large map. This is generally referred to as app-db. Internally, this map is a ratom.


This page is a preview of Tinycanva: Clojure for React Developers

Please select a discussion on the left.