Using normalizr to work with nested data in Vue & Vuex

Tue, Jun 6, 2017 - 5 minute read

Compared to older frameworks, developing an application in Vue is a real treat. However, even when working in Vue and Vuex, things can quickly become complicated. Especially when working with state objects that go multiple levels deep. I ran into this problem while developing and it has costed my quite some time to figure out an elegant solution for this. Since I haven’t been able to find proper examples on this online, I want to share my experiences and some code here.

the problem

When data is returned from an api, it might contain multiple _entities _that you want to work with separately. For example, when making an online quiz application, your data might look like this:

For this specific example it might not be that clear what the problem is. But say, we want to re-use the same question over multiple rounds? It is possible to literally copy the question object to each round object, But this means updating this question later one will require us to traverse through all the rounds and search and replace the question. Instead, we want each round to contain references to the questions, so we can easily reuse the questions in multiple rounds.

The solution

A possible solution lies in _normalizing _your data, which basically means converting it from a nested object, to grouping it by data type. If your data is a list of quiz rounds, each containing questions, with each question containing multiple answers. This is a typical example of nested data. The nested “shape” of data works fine for rendering html when passed to a Vue component, but updating in Vuex might become a problem.

Vuex works best with flat data, therefore it’s important to keep our store as flat as possible. We use normalizr to flatten api responses to multiple entities and update those in the store.

Normalizr

Normalizr is a framework agnostic library build for building flat object structures from nested ones. It does so by looping through an object according to a _scheme. _For this to work, a scheme must be defined in which we define the relationship between the various nested entities. In the quiz example these entities would be:

This will result in an object that contains references to the entities instead of the complete ones:

Integration with Vuex

So how does flattening our data help in Vuex? Vuex store mutations become quite complex when using nested data, since they need to be able to access all parent entities from root to target in order to update just one.

When data is normalized however, the answer can be updated simply by following the path: store -> answer(id).

Since all of our entities are now being saved in a similar way, it becomes quite easy to create a generic action and mutation for updating your entities in the store, based on an API response for example like this:

By implementing these two functions your application will not magically work with normalized data. However, if done correctly, normalizing data can save you a lot of time when your application grows more and more complex.

Full example

update On request I decide to provide a full example on jsfiddle. This will hopefully give you a better image of how all of this stuff comes together!