Overview
We’ve created a boilerplate based on years and many projects in React Redux that can help get you started with:
- Routing
- Authorization
- Authentication
- Code Organization
It’s based on create-react-app and also demonstrates our High ROI Testing approach.
The Big Two
There are two things that we recommend doing that we call our big two. React Redux has some great performance optimizations but if you aren’t careful it’s easy to get into bad situations like the ones described in Common Problems in Naive Redux Implementations. However, below are two simple things you can do that will help you avoid these situations.
Only Update State in Selectors
We discuss the selector patter in our boiler plate here and we can’t stress enough how important it is to follow this approach. If you only access state in selectors then you will effectively define an API for access your state atom and this will allow you to easily change the details of your state atom shape over time. You will want to evolve your state atom design and as your code becomes complex you will want to consider patterns like state normalization and reducer composition. Having selectors between your components and state will make this trivial to do.
Install redux-immutable-state-invariant in Dev Builds On Day One
While you should always follow Redux’s Immutable Update Patterns it is strongly recommended that you give yourself a safety net and we like the redux-immutable-state-invariant middleware. It’s the simplest way to keep your state atom following immutable update approaches because all it does is throw an exception if you mutate state. We recommend configuring it in your non-production builds and you should be able to easily find and fix state mutation problems. There are other tools out there like immutable.js but we recommend against using these tools for two reasons (1) it increases ramp up as you have to learn new syntax for doing something as simple as updating an array element (2) it will delay the pain points in your state atom design that will have you looking to improve it with patterns like state normalization and reducer composition.
Common Problems in Naive Redux Implementations
We’ve seen it on projects big and small. Once your app starts getting big you can find that you start having the types of problems below.
Views not updating
This happens because Redux assumes your model is immutable and has performance optimizations based on this assumptions. For example, connect()
will prevent your component from rerendering if the results of it calling mapStateToProps()
has changed and more importantly it uses a shallow compare to figure out if the results have changed. This means that if you are returning { foo: state.foo}
and then in your render()
method you are doing this <p>this.props.foo.bar</p>
then if some other component or code mutates like this state.foo.bar = 'something new'
then your component won’t rerender as state.foo
hasn’t changed (it’s still holding the same pointer). You can find the redux mutation best practices here.
Having to do deep dirty compares
One way to get out of the situation described in Views not updating above is to deep clone your state when it comes out of reducers. This will enforce that your state has changed and allow your views to update. I’ve seen this having to be resorted to on a large project because by the time the views stopped updating there was so much code and it would have been to hard and expensive to fix all the state mutations. However once we did this then we had to use _.isEqual()
from lodash to do deep quality compares in our componentWillReceiveProps
methods which caused huge performance loses.
Large cost for changing your state atom shape
Another thing that can happen over time is that your components will be doing things like this
mapStateToProps(state) {
bar: state.foo.bar
}
Which seems harmless enough but the problem is that it couples your component with the state atoms shape and over time has things get really complex it can make refactoring your state atom cost prohibitive which can lead to overly complex and redundant state atom design.
Repository
https://github.com/RyanAtViceSoftware/vice-react-boilerplate
Video
This video talks through a lot of the concepts in the boilerplate