Redux By Example: Part 3

John Tucker
Frontend Weekly
Published in
3 min readMar 30, 2017

Introducing the important concepts of action creator and selector.

This article is part of a series (starting with Redux By Example: Part 1) of articles that, through a series of progressively more complicated examples, illustrates a number of core Redux concepts. These examples are provided as Node.js applications; without any browser or React complexities.

Normalizr

note: While the use of normalizr is consistent the tutorials provided by Dan Abramov (developed Redux), I have begun to move away from using it with projects with normalized APIs (unnecessary extra overhead).

While we implemented each of the CRUD operations through the previous examples, we are going to use the normalizr module to streamline the reducer’s code.

The crux of the problem in the previous examples is that the structure of the action’s value differs across FETCH and the other ( ADD, DELETE , and UPDATE ) actions. In the case of FETCH it is an array of object and the others it is an object.

The normalizr normalize function converts both the arrays and objects (used in the action’s value) into a common data structure that parallels our store structure, for example for FETCH it becomes.

{
entities: {
items: {
m: {
id: 'm',
name: 'mango',
description: 'Sweet and sticky'
},
n: {
id: 'n',
name: 'nectarine',
description: 'Crunchy goodness'
}
}
},
result: [ 'm', 'n' ]
}

and for UPDATE it becomes

{
entities: {
items: {
m: {
id: 'm',
name: 'mango',
description: 'Sweet and super sticky'
}
}
},
result: 'm'
}

Run the example with the command node dist/normalizr.js.

Looking at the example’s source code:

  • Compared to our earlier examples, the reducers are greatly simplified (got rid of the need for the loop and map).
  • Incidentally, we updated the FETCH action to completely replace the ids instead of appending them. As the FETCH is typically done once early in the application startup, this distinction is more of a formality than a necessity. But, should one choose to FETCH later it is important to not double-up on entries.

Action Creators

Keeping in mind that the purpose of Redux is to provide a protected mechanism to manage application state, it is important to decouple the state management implementation details from the rest of the application.

Thinking of the previous example, having to use normalizr and the schema objects when dispatching events (with React, done in components) is such a tight coupling.

The solution is to create functions, action creators, that encapsulate the implementation details.

Run the example with the command node dist/action-creators.js.

Looking at the example’s source code:

  • This application has two action creators, fetch and update that shield the rest of the application from the implementation details, i.e., normalize , itemsSchema, and itemSchema .

Selectors

Similar to the problem that action creator solve, selectors encapsulate the implementation details when responding to events.

Run the example with the command node dist/selectors.js.

Looking at the example’s source code:

  • This application has two selectors, getItem and getItems that shield the rest of the application from the implementation details, e.g., byId and ids.

The Next Part

In the final part, Redux by Example: Part 4, we will address a subtle problem with the getItems implementation and further encapsulate handling of the items (the fruits).

--

--

John Tucker
Frontend Weekly

Broad infrastructure, development, and soft-skill background