This tutorial is out of date and no longer maintained.
At some point in your complex React project, you are going to need a state management library. Redux is a good choice because of it’s simplicity and centralized data management. This piece is a practical approach to the fundamentals of Redux in building React application for managing a book store.
If you are unfamiliar with the Redux idea/philosophy, Carly Kubacak previous article will prepare you for this so I suggest you have a look at it first.
We have been writing about React with consumable examples without having to seek the assistance of a state management utility. So why now?
Pete Hunt said if you ever doubt if you need Redux or not then you do not need it. On another hand, if your app is complex and fall into any of the following, then you should consider Redux:
If you ever doubt if you need Redux or not then you do not need it. - Pete Hunt
DRY is my favorite principle in software engineering and I bet you like the idea too. For that reason, we are not going to write boilerplate code to get started, rather, we will use an existing solution.
Cory House’s Slingshot is awesome and covers everything you will need in a React-Redux app including linting, testing, bundling, etc. It is also has a high acceptance in the community with over 4k stars on GitHub.
Clone Slingshot to your favorite working directory with the following:
We need to prepare the cloned repository by installing dependencies and updating the package.json
. Cory included an npm command to do all that:
You can run the app now with
The -s
flag reduces noise in the console as Webpack which is the bundler will throw a lot of details about bundling to the console and that can be noisy and ugly.
We do not need the app in the application so we can just remove it with a single command:
We are good to start building our app.
Before we dig deep into building our application, let’s have a shallow approach by building a book management page that creates a book with a form and lists the books. It’s always important to keep the following steps in mind so you can always refer to them when building a React app with Redux:
createStore
connect()
This tutorial is multi-part. What we will cover in this part is getting comfortable with this flow and then in the following parts we will add more complexity.
We will make some of the pages available using React Router but leave placeholder text in them. We will just be making use of the manage book page.
If you are unfamiliar with the difference between UI/Presentation components and Container components, I suggest you read our previous post.
Let us create 3 components: home, about, and manage page components. We will put these components together to make a SPA using React Router which we covered in full detail in a previous post.
Home Page: Create a file file named HomePage.js
in ./src/components/common
with the following:
About Page: Just like the home page but with slightly different content:
Book Page: This page will contain everything for creating and listing books. We won’t abstract Ui components for now. We go against good practice and put all our codes here. This can be refactored later. This is just for clarity.
Root: We will create a root component now to house each of the other page components. React Router will also come into play here as we will use the Link
component for navigation purposes:
We are using a functional component here which is one of the ways to create a React component. Passing the children down is a good way to inject the child components as determined by the router.
Routes: Let’s now create component routes for this application. The file that will contain the routes can be at the root of your project if the project is a small one or you can split them up if you prefer to:
You can see how the parent route is using App
as its component so all the children routes’ components will be rendered where props.children
is found in App
component.
Entry: The entry point will render the application with its routes to the DOM using ReactDOM
’s render method:
We are passing all the routes to the router as a property which is one way of defining Router’s routes. As a reminder, if these routing terms are strange to you, I recommend you read a post on React Router.
At this point we are set up but our app will run with errors because the books props passed on to the Bookpage
component is undefined. Let’s keep moving though.
The next step as listed above is to identify relevant actions and create them. Actions are object payloads that are identified by a required property type
. Action creators are methods that wrap and return the action object. At the moment, we just need an action which we will create in the actions
folder in the src
directory:
Now, this action is ready to be dispatched by the store but no rush yet. Let’s create the reducer that updates the store first.
Reducers are used to update the state object in your store. Just like actions, your application can have multiple reducers. For now, we just need a single reducer:
When the store dispatched an action, all the reducers are called. So who do we know which action to act on? By using a Switch statement, we determine which action was dispatched and act on that.
There is a big problem though. Reducers must be pure functions, which means they can’t mutate data. Our current implementation of the reducer is mutating the array:
How do we make an update without mutating? The answer is to create another array of data and update it’s content with the previous state and that changes made:
The spread operator just pours out the content on the array into the new array.
I mentioned in the previous step that we could have as many reducers as we want but unlike actions, Reducers are not independent and can’t stand alone. They have to be put together and passed as one to the store. The act of putting multiple reducers together is known as reducer combination and the combined reducer is the root reducer.
It’s ideal to combine reducers at the root of the reducers’ folder:
The combination is done with combineReducers()
from the Redux library.
The next step is shifting focus from reducers to store. This is the time to create your store and configure it with the root reducer, initial state, and middleware if any:
We do not need any middleware now so we just leave that out. The createStore
method from redux
is used to create the store. The createStore method is wrapped in an exported function configureStore
which we will later use to configure the provider.
The Redux’s store API includes (but not all):
It is very inconveniencing to have to use this methods all around your react components. Dan, the founder of Redux built another library react-redux to help remedy this problem. All you need to do is import the Provider
component from react-redux
and wrap your entry point component with it:
Not only do we wrap with Provider
, but we can also now provide the store
to the Provider
component that will, in turn, give the descendants of this entry component access to the store.
Wrapping our entry component with Provider
does not mean we can go home happy. There is still a little job to be done. We need to pass down the states to our component’s props, the same goes with the actions.
Best practice demands that we do this in container components while convention demands that we use mapStateToProps
for states and mapDispatchToProps
for actions.
Let’s update the BookPage
container component and see how the flow gets completed:
mapStateToProps
now makes it possible to access the books state with this,props.books
which we were already trying to do in the component but were shy to run because we were going to see red in the console.
mapDispatchToProps
also returns an object for the respective dispatched actions. The values are functions that will be called when the actions are dispatched. The value expects a payload that you can pass in as well when dispatching.
The connect
method now takes in these 2 functions and returns another function. The returned function is now passed in the container component.
Now you can run the app with:
We should have a working demo like the one in the image below:
We just had a quick look on React with Redux but this can make a real app. In the next part of this tutorial, we will try to draw closer to something real like making async requests with redux-thunk
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!