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?
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.
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.
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.
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;
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With