Using Redux in React apps has become the industry standard for building scalable React apps, but with Angular, it is not so obvious when to use Redux because Angular already provides services, which can manage state.
Through my work with clients I have come up with the three ways I see Redux is used with Angular:
- Hybrid reactive app: Use Angular services for most of the state management, but use Redux for certain use cases such as 1 to many communication and undo functionality.
- Pure reactive app with commands and events: Use Redux for all state management and update the store with commands as well as events.
- Pure reactive app with events: Use Redux for all state management, update the app state by calling service methods and update store on events.
Hybrid reactive app
This is my recommended starting point for an application. Redux does add complexity and should only be applied to fix the pain of state management in a big application.
The idea is to not to introduce Redux in the application at all until the application has become hard to manage without. Reasons for introducing Redux includes:
- A lot of 1 to many communication, where Redux helps by centralizing the state that other components can subscribe to.
- Deep component nesting and change detection optimization with onPush, where components can’t get state directly from a service nor trough input and output and instead need to subscribe to state changes and trigger change detection for the component either by using the async pipe or .markForCheck in the subscription.
- Undo/redo functionality, as this can easily be implemented with the state in the Redux store.
- Query param synchronization with the store. I will write a post about this later.
- Caching with the store, as Redux can save you from cluttering your business logic with caching code and do more aspect-oriented programming.
- Use it for logging middleware on certain events, such as HTTP requests.
Pure reactive app with commands and events
This pattern is similar to the CQRS pattern as it contains commands that trigger some modification of the app state, that are separated from the reading (query) of the app state. These commands can have side effects, which are events, that also causes changes to the app state.
With this pattern the business logic is typically in the reducers and/or epics (reducers that causes events to be triggered instead of causing state changes directly). This is a typical setup for React apps to use this pattern but for Angular apps, I prefer to avoid using commands with Angular as I find it complicates the control flow and instead I prefer calling service methods for state changes and hence use services for encapsulating business logic.
In this sequence diagram we see that fetchData (command) is getting dispatched to an epic to fetch data, which will do the fetching and after this dispatch the event fetchDataChanged.
Pure reactive app with events
As the application has scaled to a considerable size and matches some of the use cases above, this is the Redux pattern I will recommend. With this pattern, the components and services are completely stateless and all state will be contained in the Redux store. The state is changed by calling service methods that dispatch events as side effects, which will change the app state.
In this sequence diagram we see that fetchData (service method) is getting called on a service to fetch data, which will do the fetching and after this dispatch the event fetchDataChanged. Notice how this flow is simpler than the flow with commands because of less indirection and easier control flow of the code.
We went through three ways to use Redux in your Angular app. My recommendation was to start with the hybrid solution and when the app has scaled to a considerable size, migrate to a pure reactive app with events and use services for encapsulating business logic and controlling state changes.