Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to model relational data in an Om-like immutable app state

I'm trying to decide whether to use a more traditional Flux implementation or to go with an Om-like structure. I really like the idea of using a single immutable app state object with cursors in javascript, but I'm unsure how to model relational data. I'm looking at using something like Morearty.

My question is how do I avoid duplicating data and deal with nested relational data sent from the server? Let's say I have REST endpoint that gives me inventory and each inventory item has a nested vendor. I also have an endpoint of vendors. I want to have a list of all vendors in my app state, but also reference those vendors on my inventory items. When I make an update to a vendor, I want it to change on all the inventory items that reference that vendor.

Does an Om-like structure work for this kind of application or would a more traditional Flux style app with discreet stores be better?

like image 440
Gabriel Syme Avatar asked Oct 31 '22 09:10

Gabriel Syme


1 Answers

You probably want to look into something like Redux as your "flux" framework. It's absolutely excellent — we use it at Docker. Here's why it's good and how it can help you.

Why use redux?

It uses a single store model. All stores save state within Redux itself in their own key. An example of the state Redux saves is:

{
  vendors: [{...}, ...], // The "vendor" store updates this part of the state
  inventory: [...] // the "inventory" store updates this part of the state
}

And Redux, or a redux provider, is the parent of all components. Therefore all components receive the state as props.

How does a single store model improve things?

  1. Each individual "store" which responds to actions within Redux updates only one part of the state object. For example, the "vendor" store only updates the "vendor" key of the state. The individual store is given the current state each time an action happens. This makes stores entirely pure. This is great for testing, immutable data, hot-reloading, rewinds etc.

  2. Because your single top-level Redux store saves all state, each component can receive this state as props and automatically re-render whenever this state changes — even from unrelated components out of hierarchy.

Here's an example of a single store in action, so you can get the idea:

import assign from 'object-assign';
import consts, { metrics, loading, URLS } from 'consts';

const actions = {
  // As you can see, each action within a store accepts the current "state" 
  // and can modify that state by returning new data.
  [metrics.FETCH_METRICS_PENDING]: (state, data) => {
    return assign({}, state, {status: loading.PENDING});
  },

  [metrics.FETCH_METRICS_SUCCESS]: (state, data) => {
    return assign({}, state, {status: loading.SUCCESS, metrics: data.payload});
  },

  [metrics.FETCH_METRICS_FAILURE]: (state, data) => {
    return assign({}, state, {status: loading.FAILURE});
  },

  [metrics.OBSERVE_METRICS_DATA]: (state, data) => {
    let metrics = state.metrics.slice().concat(data.payload);
    return assign({}, state, {metrics});
  }
}

// This is the single method that's exported and represents our store.
// It accepts the current state as its primary argument, plus the action
// data as a payload.
//
// This delegates to the methods above depending on `data.type`.
export default function metricStore(state = {}, data) {
  if (typeof actions[data.type] === "function") {
    return actions[data.type](state, data);
  }
  return state;
}

How can this model relational data?

Each time data is requested via an action creator it can dispatch multiple actions which update the vendor and inventory state together. This will be reflected in your app within one render.

like image 197
tonyhb Avatar answered Nov 07 '22 22:11

tonyhb