Co-authored: Daniel Stankevich
TL;DR: React is better if you use Flux…
Our Journey with React
Having recently decided to embrace React.js for some of our front end applications we soon reached the limitations of simply wiring components together. When you start with a simple React application you will create many components. At some point a change in one of these components will need to update another component. eg. If you change a Price text field, you need to change the page title to reflect that.
Initially you can start by using callbacks. When you create your Price component, you will pass in function call handlePriceChange from the parent component. This parent component will then be responsible for updating the Title component.
This works with a small number of components, but when you have many deeply nested components you start to run into the following problems:
- Deeply nested callback chaining to maintain state throughout the application
- Tightly coupled components
- A lot of wiring code
- Adding and moving components (even for layout changes) becomes difficult
- Hard to understand side effects of changing the state for a component
Working with Flux
What we liked about flux
- Highly decoupled components
- Data flows in a single direction
- Application state is maintained in a single place (Stores)
- Components do not keep application state, which makes it easier to make layout changes to the application without having to rewrite lots of code
What we didn’t like
- Default Dispatcher was overly complex for our needs
- Single large Dispatcher to handle all types of events
- Didn’t need promises (mainly working with local storage)
- More complex to explain to new team members
Our Flux implementation
In the end we decided to take inspiration from Flux to implement something simpler that better suited our needs.
We decided to combine the concept of the Dispatcher and Stores. When a component is created it will register its interest in the store. If the component needs to change the data in the Store, it calls the set function and all components registered with that Store will have their callback functions executed.
For our application we use a single Store per domain model, this fits in well with a microservices architecture as you can easily have that store sychronise to the backend service if required when it changes the state of the application.
- Combined dispatcher and Store
- Components register their interest in changes to the store when they are created
- Components update the store when they need to change application state
- Store emits change events to all registered components
- Single store per domain model (works well with microservices architecture)