Mike Vercoelen
15 Feb 2018
•
3 min read
In this article you’ll learn how to setup a scalable, simple and consistent technique for your dataflow in your Redux apps.
So you’ve created some stuff for the interwebs with React and Redux, super great, awesome well done. Maybe you’ve even created an app that has some users: even more awesome.
I’ve been there and after working on a few projects that had over 100k lines of code frontend wise, I found myself struggling with handling data in Redux in a scalable and consistent way.
I’ve tried ducks and numerous of other ways of getting it right. When I landed in a complex e-commerce platform, me and my frontend besties discussed and discussed and came up with a solution: the entities
reducer.
So let’s talk about the entities reducer, see it as a mini database for your frontend app. It’s a place where all the data of your application lives. All queries and modifications will be in one place, so you and your team will know exactly where to look for handling data.
The best way of explaining the entities reducer is by example. Let’s dive right in.
The example we are using will be a chat application, thinking about a chat application what kind of data “entities” do we have:
Now you can imagine where the name “entities” comes from.
There are a few dependencies that are optional, but used throughout all the examples in this article. I highly recommended them for managing your data.
import { fromJS } from 'immutable'
// TODO: you should put this in your `utils`, and make a helper, so you can reuse this because it's awesome
function createReducer (initialState, handlers) {
return function reducer (state = initialState, action) {
if (handlers.hasOwnProperty(action.type)) {
return handlers[action.type](state, action)
}
return state
}
}
// The chat application has: `users`, `rooms` and `messages` as data entities
// We use `fromJS` to make it an immutable object
export const initialState = fromJS({
users: {},
rooms: {},
messages: {}
})
export default createReducer(initialState, {
// The reducer will go here...
})
Now what kind of actions do we have in our mega awesome chat app?
Just imagine these actions working, by using thunk or sagas. It does not matter for this article how they work, just pretend they work and get triggered.
IMPORTANT NOTE: All the actions should have a payload created by normalizr
So remember: by using this technique, all the data of your application will be in ONE place only. So all actions that do something with your data, should also be handled in this reducer.
First we need to add the following helper function to our fresh new entities
reducer. This helper function will help us easily set data on our entities reducer.
const mergeEntities = (state, { payload }) => {
return state.withMutations(state =>
Object.keys(payload.entities).reduce(
(_state, entity) => _state.mergeDeepIn([entity], payload.entities[entity]),
state
)
)
}
If you take a good look at mergeEntities
you can see that it basically handles an action for us, the first argument is the state, and the second destructs the payload from an action.
If you take an even closer look: you can see it accesses payload.entities
this comes from using normalizr
If you're interested in working with React.js full time, check out all of our React jobs here on the job board!
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!