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
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
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.
(fn ) and
#() have the same behavior - both call
dispatch and set the Reframe loop in motion.
Step 2 - Event handlers#
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-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
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.