Skip to main content

State management

Every app will need to manage their own state and choose an appropriate strategy and software stack depending on its own scope and platform. Regardless of using something like Redux, Recoil or React Context what we store remains the same. The differences between application state arise depending on the application purpose.

Types of state#

We differentiate between 4 types of states in our applications:

  • Application level shared state
  • Inter-application shared state
  • Component level state
  • Shared component level state

Application level shared state#

Information that is shared amongst multiple components or needs to be persisted will end up in the applications state. Examples of this are:

  • current user details
  • current order (shopping cart)
  • active payment
  • recently viewed products
  • user preferences
  • application settings

This will be the state that is managed in a state management library (Redux, Recoil, MobX, Context). It will house the most important entities that revolve around the primary purpose of the application. So for example your current order in a sales application. The application level shared state comes in 2 flavours:

  • server backed state
  • local state

The server backed state will be data retrieved from the EVA backend. It will be updated (synchronised) when users take action or an external trigger (like SignalR) indicates us to do so. So for example the current user profile or the active sales order details.

The local state revolves more around the application itself. This data will likely be persisted to local storage solutions including cookies, session storage, mobile platform key/value stores. Most likely candidates are remembering recently viewed products, language preference or current EVA endpoint for applications able to switch endpoint.

Inter-application shared state#

Separate applications can synchronise their state through external means. This can be a server side session with SSO support or a local storage based exchange of data on the same domain. Setting up this communication is done on application startup and will remain active in the background for the entire lifetime of the application. Example of this kind of state sharing/synchronisation is a subscription to order updates for the same ID or same domain local storage synchronising viewed products between browser tabs.

Component level state#

Components in frontend framework are initialised with a set of properties or data. This data represents state. This state may or may not be persisted (locally) or it can be inferred from the current navigation stack (url). For example the global application state has an active order and an on-demand print receipt component will be started with the currently active order ID. In the background the application state can change (a new order is started) while the dialog is still active. The print receipt component has a local state containing the order ID which will be discarded when the receipt component lifecycle ends.

Shared component level state#

Sometimes a set of data or properties needs to be shared amongst a (small) cluster of components. If there is no use for this data outside this cluster of components it has no place in the application level state. A container components exposing the properties to its child components is usually the way this presents itself. Best practices for these include a smart container component managing the data and a collection of dumb components only handling the display of a portion of the data. Certain frameworks like React provide options with hooks to forgo the container but the principle remains the same.

Application level state vs on-demand service calling#

Volatile information that would be re-requested any time a user interact with a component should not end up in the application level state. Examples of this are:

  • postal code lookups
  • server-side validators like email validation
  • password resets

Reference lists#

Something that deserves a special mention are (unfiltered or paginated) reference lists. It might be beneficial to only retrieve these once during the application lifetime (or per time period). Adding them to the shared application state and persisting them is recommended. Examples of this are:

  • country code lists
  • currency lists
  • enum lists

These lists are likely seldom updated. Starting the application with the last known values and updating them in the background can be a nice performance.

Application level state modifying actions#

These are the calls that modify an object that is in the application level state. The best example for this is the active order state and the calls that add or remove products to it. The order itself is obviously in the state but all the add/remove/modify calls will not have to be. As long as the order entity is updated after the modifying actions you can keep other calls on-demand outside of the state. Listening for order updates originating outside the application itself (using signalr) should also sync the active order with the EVA backend.