Real store’is: Local stores (part 2 of 3)

MobX stores definitions in a real-world app

José Manuel Aguirre
ITNEXT

--

This post show the “State Management” side of timefic.com, which means we are not talking here about React components, rendering into the dom or handling user events. It will be about how to organize data (state) and how to model any app based in 3 kinds or families of stores:

  • Utility stores: Stores that are “architectural” to the app (and probably the app you are building now) so they can be used by all the modules or services defined in your “big picture”. See the article here.
  • Local stores: Stores that are persisted locally or not persisted at all. They hold temporary data but are critical for the client-side experience of your users.
  • Domain stores: Stores that are related to a specific domain or service and where the business rules have its home.

So, in this article, we will be looking at the Local Stores! But first, let’s define when it’s necessary to have them.

Photo by Daniel Tseng on Unsplash

How can I know if a piece of data should be in its own store?

Although we haven’t seen yet the domain stores, it’s pretty clear that these stores are necessary: you have one table in your database and its data needs to be accessed in the client? Then you define a store. It’s 1–1 relationship. For example: ‘agreements’ (the table in MongoDB) will have ‘AgreementsStore’ on the client side.

But, local stores do not have a table in your backend, so how to know when are they necessary?

  • UI State Managment: Your UI is not displayed all at once. There are hidden menus, popups, tabs. There are lists of elements and you have one selected. It’s a good idea to have 1 store (and 1 only) for all this data and be able to access it from your UI and the other stores.
  • Instances of Utility Stores: Generic stores we see in the first part of this article needs to be instantiated. For example, you will define locally an AlertsStore with the definitions (alerts) that are needed for the specific module you are developing.
  • Cross-domain Business Rules: Business rules are all over the stores. Each store can have it’s own rules like AgreementsStore or CommentsStore do. But, in some cases, there are rules that cross the boundaries of a particular store and have a relevant role inside your app. In timefic, for example, there is a ChecklistStore that holds the rules to convene a meeting, like minimum anticipation for meeting date, have an agenda with times, and a purpose, among others.
  • UI complexity encapsulation: Sometimes you need to define a “whole store” just to hide complexity away from your components. For example, in timefic, there is a SyslidesStore (Slides generated by the system) that needs to be shown when certain conditions are met, like a new agreement that needs to be voted or when the time is up for the current topic.
A fragment of the Control Store in the Dashboard app.

Some concrete use cases

There can be a broad possible uses cases for local stores, so I give you an example of the ones I am using:

  • State: A single store that holds simple values (typically booleans and strings) that are necessary all over your app. Like React state is at the component level, this is the state at the application level. The “single source of truth”.
  • Alerts: Here you store the metadata (the definition of the types of alerts you need), the actual data (the alerts generated) and the methods to add or remove them. It’s a local store because you will not be touching your backend here.
  • Clocks: A local store, synced with the clock of your backend every X seconds, that is in charge of informing the current time to your time-based business rules and the rest of the stores interested in this data.
  • Streams: Stores that holds values coming from an external source, like an api or a streaming service. For example, when a user is typing in the chat, the other peers see a notification. Here is where you can publish and subscribe to this notifications.
  • Syslides: An abbreviation for “System slides” or slides that are generated by the system. This store takes input from a subset of the domain stores and the ClocksStore, to create events that some React components will be aware of. This complexity is encapsulated here to avoid having complex components.
  • Control: A local store, also to encapsulate UI complexity. In this case, a meeting has a sidebar menu that shows some actions you can execute: open the meeting room, open the meeting planner, download the minutes as PDF, delete the meeting, etc. These options depend on the meeting status, the user role at the meeting, the account status. So this logic is better here than directly in the UI.
  • Grants: Similar to the store above, in this case, there is a multi-step process with options available (or not) to the user that depends on the meeting status, the user role, the clock, etc.
  • Checklist: Another case similar to the above, in this case, this one is 100% business rules that allow or deny the user to send the invitations, confirm the meeting or send an update.

I think this post may be very specific to the uses cases I found at my meetings app, but it may help you think about your use cases and find some similarities with mine’s.

The next and last part of this article we will be looking at domain stores, or stores that hold the main data your app is about and, because of that, they are persisted in your backend.

--

--