On this page:
There is a fundamental question you should know how to respond before learning Redux, the question is: What is the state of an app?
Let’s try to answer that question with plain English, let’s not think of React or Redux for a moment, all in all, any app has state regardless of the technology. To help us understand what the state of an app is, we are going to ask two simple questions:
In my experience teaching Redux at reactgraphql.academy I’ve found cases where everyone in a workshop seemed to agree that just the selected tab is part of the state, and in other workshops, everyone seemed to agree that the only thing that was part of the state was the data that came from the API 😲
It might be obvious to you, or it might not, but I always find very useful to make sure we are all on the same "state" before moving forward.
To answer the two previous questions, imagine that when a user runs the app shown above, by default the selected tab is “Day”. When the user selects “month” then the app requests the data for a given month to an API and displays the new chart. Now if we tell the user that if she/ he switches to another app, and when she/ he comes back the app will be in the same “state”, what do you think the user expects to see? The answer is tab selected equals month and the corresponding chart. So the answer to the original question is both, tab and chart, are part of the state.
Traditionally, in front-end, we would store the selected tab using metadata in the UI (example an “active” CSS class, or a “data-” attribute), and the data from the API in a JavaScript variable. That’s problematic because we are storing the state in two very different places, HTML for the active item and JS for the data of the items. That’s a bad idea in a declarative paradigm like the one React embraces (check this link to learn more about React and the declarative paradigm).
Any questions? Hopefully, it was simple enough. Let’s zoom in more to look at the different things the box can do for us.
The whole state of the application is represented in a single JS object, called the state tree.
The state tree is read-only. The only way to change the state tree is by dispatching an action.
{ type: RECEIVE_THREAD }
Wait a moment, before talking about the 3rd principle, we need to understand what we’re referring to when talking about pure functions:
OK now we are ready, the third principle:
The state mutations in your app need to be described as a pure function called reducer that takes the current state and an action and returns a new state:
A reducer has 3 responsibilities:
The following CodeSandbox is a reducer that implements a counter. The state is an integer that can be incremented or decremented
It glues the 3 principles together. You can think of the store as the previous “box” example.
The store is a JavaScript object that implements 3 methods:
This is a simplified version of Redux, and although it works there are optimizations that have been removed for simplicity.
On line 8 of the gist above you can see why a reducer must always return some state. As we mentioned earlier, every time an action is dispatched all the reducers are invoked and receive that action. If the action type is not relevant to the reducer, the reducer must return the current state otherwise the state in the store will become undefined (line 8).
You can see a working example of our simplified version of Redux in the following CodeSandbox
Wait, so far all the examples use one reducer, but I said that real-world applications have many reducers; would our simplified Redux work in a real-world application with many reducers? The answer is yes.
That’s one of the things that makes Redux so powerful, every piece of the puzzle works in isolation. If we have many reducers we don’t have to change our Redux implementation to receive many reducers. We just need to combine all our reducers into one. That combined reducer is the parameter of the createStore.
So how do we combine all the reducers? we just need to add another piece to the puzzle, a combineReducers function:
// The combineReducers is the other piece along with createStore you will use to // implement Redux in your application. The combineReducers will combine all the // reducers into one and then you'll pass it to createStore. // Check this video to see an in detail explanation of how it works: // https://egghead.io/lessons/javascript-redux-implementing-combinereducers-from-scratch export const combineReducers = (reducers) => { return (state = {}, action) => { // for every reducer (don't confuse our "reducer" functions with the // array.reduce method we are using below) we combine the state that every // reducer returns return Object.keys(reducers).reduce( (nextState, key) => { nextState[key] = reducers[key]( state[key], action ) return nextState }, {} ) } }
One of the two co-authors of Redux, Dan Abramov, explains the combineReducers function step by step in this video
In the next Codesandbox we are our previous createStore function with the combineReducers to combine two reducers:
Redux can manage the state of any application, not just React. You can see this in the previous CodeSandbox example where Redux is used in a Vanilla web application, there is no React.
I recommend watching the following videos from Dan Abramov, co-author of Redux, which explain Redux in more detail https://egghead.io/courses/getting-started-with-redux
We won't spam you as per our Privacy Policy.
Share this on:
Comments? Shoot me a tweet @reactgqlacademy !
GraphQL Evening with Round Table 💥 Online
London, UK
Prices & more details