
Redux: Single Source of Truth
Art of the state
If you’re familiar with Redux I’m sure you’ve heard the term “single source of truth”. Those of you coming from varying frameworks and backgrounds might have different interpretations of what that exactly means. I’d like to do my best to make sense of the following: what we mean when we say “single source of truth”, the best ways to insure you are maintaining that single source, and how to structure your app to be flexible enough to make this single source concept a reality.
Before we get into more of the technical terms lets cover the basics. The term “store” gets thrown around a lot in Redux. You might even have been confused at one point. I’ve heard it all - “reducers most have stores”, “state is equal to the store”, “app level store versus component store”. All of these concepts are true in their own right, but they don’t capture the holistic understanding of what we are trying to capture in the store or our ‘single source'. At the most basic level the store is an object that holds the state.
Reducers
Reducers are functions that listen for specific signals from the application. When their name is called, or that signal is dispatched, they capture information and inject it into the state. They do this by adding to the existing state. They do not remove information. In ES6 we use the spread operator (…state) in ES5 you can use Object.assign. The reason is we want to inject the payload into our state, not rewrite our state to reflect our payload. We say all reducers must have a state because at it’s essence a reducer without state is just a function that populates an object. Another way to think of reducers is as an internal event listener. With event listeners we normally have user interactions such as “onClick” or “onSubmit”. Redux has taken this pattern and integrated it into it’s model language. Its important to note that all reducers are running at all times. They are constantly invoked. You can think of them as patrons at a deli counter waiting for their order. They know their own order, and when the deli owner calls out the order, say “pastrami on rye”, they jump to the counter to pick up the sandwich. In this analogy the cash register would then be the store. As patrons get their order they proceed to the checkout line to pay for their meal. We’ll get a bit further into reducers a little later. First let address the three parts that contribute to the one way directional pattern of Redux.
Actions, Types, and Payload
An action is a function that is invoked when we want to pass the the “type” or the signal as referenced in the previous analogy. Actions are singular. They emit one single type and have the potential to pass along a payload. Payload refers to what is being passed along, in this case it is the text we are receiving via the arguments. Below is an example action.
const exampleAction(text) {
return {
type: "ACTIVATE_SOMETHING",
payload: text
}
};This action can be called within a react component when linked up properly through Redux’s “connect” function. The common convention for linking them is by creating a function, usually name one of the following: mapDispatch, mapToDispatch, mapDispatchToProps. This function takes in the callback ‘dispatch’ and in its body you include the actions you would like to link to your particular component then return them wrapped in you dispatch callback.
const mapToDispatch = (dispatch) => ({
return dispatch(exampleAction);
});This is then included in the invocation of the connect function either at the bottom of the your container or in a connected file with your react component.
export default connect(mapToDispatch)(RandomComp);
The reason we want to remember how actions work is because redux relies heavily on the concept of a one way directional pattern. In order to have a single source of truth you must have a single process for information to be added and removed from the state.
Combined Reducers
At this point we understand that actions emit a signal, or a type, and pass along a payload. Reducers then listen for that signal retrieve the information and forward it along to the state. As you can imagine this can get very messy. Sure on a small scale you can manage but as the application grows you’ll find more and more complications. One example is; say you build a reducer for a phone number. You can imagine if you’re building out a social network app you might want to use that information in lots of different places. You could make hundreds of specifically named reducers all preforming the same task like: mailingPhoneNumber, profilePhoneNumber, etc… but that goes against our DRY protocol. We want to write once and use everywhere. This is where combinedReducers comes in. CombineReducers gives you the option of bundling together specific reducers to capture the state of a certain page, module, higher order component. It gives you a way to shape your data. Below I will give you two examples of combinedReducers.
import { combinedReducers } from 'redux'
import phoneNumber from "./phone_number.reducer";
import address from "./address.reducer";
import photo from "./photo.reducer";
import bio from "./bio.reducer";export const mailing = combinedReducers({
address,
phoneNumber
});export const profile = combinedReducers({
address,
phoneNumber,
photo,
bio
});In this example I show how you can use the same reducers for different aspects of your state. This separation of concerns allows for reuse of code and simplifying of logic. We now have two reducers, mailing and profile, that can be imported to any part of our app. Understanding the way combined reducers allow you to construct the branches of your state tree is crucial in maintaining your single source of truth.
RootReducer
As we build out our various combined reducers we will need a way to tie together all of our reducers in a clean -straight forward- single object. That brings us to our rootReducer. It is exactly as it’s name describes, it is the reducer at the root of your application, the final combinedReducer. Those of you familiar with React.js understand this concept already because we do this with our main component. Usually one named “app” or something generic, it is the component that we render to the DOM. All subsequent components are nested in as child components. This gives us a bit of insight as to why React and Redux work so brilliantly together, much more to come in future posts.
In very simple terms, the single source of truth is our state tree, that is not rewritten or reshaped. It gives us the availability to easily retrieve information in constant time and maintain a clean structure for the state of our application. When building out your reducers it is important to keep in mind if you are mutating data or simply appending to the state. The one way directional pattern insures that there are no changes to the state directly and the reducers serve as gate keepers to the source of truth. It’s all in the reducers. I hope this explanation is of help to you. If you have any further insights or would like to contribute or comment please do so in the section below. Happy Coding!.