With the introduction of Context in React 16.3, the landscape of React state management was significantly changed. Through the implementation of the Context API, data could now be passed directly into nested components, thus eliminating the need for prop drilling. At first glance, this seems to suggest that Context completely replaces Redux. However, as we discussed in a previous blog post, Context does not replace Redux but instead offers a much needed solution that bridges the gap between prop drilling and Redux.
Redux relies on the implementation of a single source of truth known as the Redux store. The store is the bucket which holds all the data within the app, and can only be accessed and manipulated in very specific, predefined uses of
reducers. Despite this seemingly rigid and restrictive requirement, a multitude of different design patterns can be utilized based on factors such as app size and complexity, long-term scalability, or simply personal preference. Among these design patterns, the most common are Rails-style, Domain-Style, and Ducks.
The Rails-style convention of code structure suggests that code should be separated into files within function-specific folders such as Components, Actions, Reducers, Middleware, etc. The resulting folder structure resembles the way in which many Rails projects are organized into function-specific folders for Models, Views, and Controllers. This design pattern suffices for smaller projects, but as apps grow, each of these folders can quickly become unwieldy. Each folder could contain dozens, potentially even hundreds, of files which becomes very difficult to manage.
A domain-style design pattern helps to address the issue of bloated, unmanageable, Rails-style folders by organizing files into folders based on app features such as User, Post, Order, etc. All files regarding Orders, for example, would be located within the Order folder, and that folder would then contain files for Order related components, actions, reducers, and helper functions. This file structure allows for quick access to relevant files when working on specific app features, and eliminates the need to search through large, cluttered folders and files.
While the domain-centric pattern is a big step in the right direction, our dev team at SmartLogic has found the Ducks pattern to be an even more effective way to organize our code. As in the domain-style convention, code is organized based on features of the app. The "ducks" pattern, however, combines the actions, action type constants, and reducers into a single redux file.
This consolidation of Redux-specific code leads to leaner project directories which has proved to be very beneficial as our apps grow. Additionally, when working on redux-related code, less files need to be touched. These benefits normally come at a cost, though. Combining actions, action type constants, and reducer logic could potentially result in very large redux files.
Reduxsauce is a library that provides concise methods for writing action creators and reducers. These methods allow action types to be mapped explicitly to reducers, and this removes the need to implement a switch-case statement. The reducer logic can then be defined separately from this mapping. As a result, the consolidated redux code becomes highly readable, and much easier to maintain and build upon. Additionally, each reducer function can be exported and thus more easily tested. In the end, all the benefits of the "ducks" design pattern can be maintained, while the lines of code required can be significantly reduced.
For a more in depth look into the common features and conventions of Redux and Reduxsauce, check out the presentation below: