The data journey in a SPA (Part 1 : from DB to user’s view)
By: Simon Thuillier
Tags: PHP, JavaScript, Web Development, React, Redux

Important ideas for the Front-end

Application state should be defined with immutable data structures

Though it’s possible to use plain JS object to describe Redux’s state it is very error prone as soon as your state begins growing. The general rule when dealing with React/Redux or any other JS frameworks is that updates are made when a difference between an old value and a new one is detected. If you use plain JS objects as state and naively update one attribute inside, thinking it can trigger all necessary views updates you’re sorely mistaken. In that case components who receive directly this state attribute as props might re-render but not those which receive the complete state, even if when rendering they might use the updated attribute. And simply because even if you updated one attribute, the state stays the same old object.

There is a second reason why using immutable data structures for dealing with state is the best choice : it guarantees you that, no matter how, there won’t be any accidental state update where there should not be eg., in components. To quote Alan Kay :

The last thing you wanted any programmer to do is mess with internal state even if presented figuratively.

The last reason to use immutable data structure is that a great library exists to do it : immutable-js.

Let’s suppose you use an immutableMap stateMap as Application state. Each time you update it using stateMap.setIn([path],value) it returns you a new stateMap object. In fact all hierarchical level between the entry stateMap object and the path destination you want to update is therefore a new object. When your reducer returns it all components who use the path destination or any ascendant of it detect the difference and it triggers re-render which is exactly what we want !

Furthermore even if creating a new object for each value update can seem cumbersome Immutable-js handles it in an optimized way extensively using shallow copying.

In conclusion on this part I would say that as soon as your state is a little complex or big immutable-js is the best way to handle it in my opinion. For more informations about benefits of it and how getting started here is good article on the topic.

Data records & stores

Using the great Redux devTool extension let’s take a look to what the front-end embedded state looks like :

Appart from app and form which are respectively my custom core app data and the subState of the Redux-Form library all other subStates are standardized stores, each containing one different kind of DTO. Each of these stores is built with the same architecture, for example for the articleType store :

And Finally all items are grouped in the items subState :

Each item in this list corresponds to a particular DTO, here an ArticleType and contains its data. They are defined as a particular Immutable-js type : the data record :

Data records are created from a Record factory which needs to know about the data structure, or prototype, of our record. Defining this factory hence requires for the client code to know about the data structure somehow. That’s why the back-end code communicates metadata about DTOs indicating their available properties.

Once created a big advantage of records is that their properties can be accessed in a traditional Immutable-js way (using get or getIn functions) or semalessly as a classical JS object (using .[propertyName]) which easier their manipulation.

Normalized Data

When you need to call some linked data it is the only good way to retrieve them together from the back-end API. For example if you want data both of an article and of its owner user you get them with only one AJAX request. You wouldn’t call for the article and then only for the user since it would be a performance-killer to do that.

However once the front-end get this data it needs to be stored in a way that prevents any data duplication. In your App state one given data needs to be stored at one, and only one place. That’s why the received data is normalized using the normalizr library before being merged into stores records. Concretely let’s suppose you receive your article data under this form :

{id:36,title:’myArticleName’,owner:{id:2,name:’myUser’}}

Normalizer converts it into :

{article:[{id:36,title:’myArticleName’,owner:2}],user[{id:2,name:’myUser’}]

To do that it also needs some metadata provided by the back-end.

But once it’s done each DTO in the stores are stored in completely non-redundant way, quite similar to the way data is stored in a relational database.

Memoized selectors

Once data is in the stores it has to be accessed by components to be rendered to the user. This is done by mapStateToProps function by which data from the application state is communicated as props to components. But not directly : using special functions called selectors.

Selectors are functions whose job is to select one or several data records from the state in the most convenient way possible for the components that will use them.

The inputs of selectors are state stores : as those are immutable data each change in ,for instance, one single record, changes the whole state and hence triggers re-rendering. This solves the problem of being sure that each change in state is indeed well rendered on the view. However it can lead to an excess of recomputations.

Hence a very interesting pattern to optimize our application is to memoize them. The memoization allows to cache the last result of our selectors and recompute it only if its input — more precisely a subset of it — changes. For this I used the reselect library. here is a very good reading to understand them.