Tutorial For Adding Redux to a React App
The front-end world evolves quickly, and it can be hard to devote time to learning a new tool. I highly recommend getting into React, and once you have done that, I think Redux is a great companion to it. It is the next step for applications as they grow in complexity.
We’re going to use create-react-app to get us going quickly. So if you haven’t done so already, lets get it setup on our machine and get going.
Setting Up The App:
We are going to use yarn here, but you could use npm if you prefer.
Install create-react-app by running yarn install -g create-react-app . Create your new app ( ours will be called my-things-app ), by running create-react-app my-things-app . Then cd into the /my-things-app directory, run an yarn install followed by yarn start .
The packages we will need are redux , react-redux , as well as redux-thunk. redux-thunk is necessary to return anything but plain objects from actions. We are going to request data from an api, and fetch returns a promise. Install these by running yarn add NAME_OF_PACKAGE for each. Your package.json file should now have those added.
Just to get us started we will get the ball rolling with a little bit of setup. First you will want three directories, ./actions , ./reducers , ./store , all in the src directory of your shiny new app. To learn more about this, check out the redux docs.
Add a ./store/configureStore.js file. I like this setup, as you add complexity it will be easier to parse it mentally, but you could write this code directly in the index.js file generated with your app.
If you were to have an app with data call Soup , and actions that are distinct for both a single Soup and a collection of Soups you may want to have two reducers, a soupReducer and a soupsReducer . In this app our only data to display will be called stuff , and for simplicity the reducer we will add can be called ./reducers/stuffReducer.js . Pluralization here is not significant other than for readability and clarity.
You will also need to create a ./reducers/rootReducer.js file. All various reducers you add will all be combined in the rootReducer.js .
Now is also a good time to add our ./reducers/initialState.js file, which will help us to ensure we always have some level of certainty about the shape of the application level state.
In the ./action add an ./actions/actionTypes.js file. This will help by having only one file in which to refer to a list of all the possible actions for the app. Also, we will need to add a ./actions/stuffActions.js for the actions themselves.
Adding Actions and Reducers:
For some background here, the docs are really clear. Essentially actions describe something happening, and the reducer responds to the action.
Starting with the actionsTypes.js here we just want to export the constants we plan on using for each action. In this case, let us start with just two simple actions, FETCH_STUFF and RECEIVE_STUFF .
We will also need the actions themselves. We are going to set this up with a function for each action type, which returns an object containing at least the type of the action.
In the case of fetching our stuff, we want to be sure we are getting our data, and so we request it by executing a fetch for our given url. We will be using the native fetch, depending on your project you may want to use a polyfill for fetch.
Next we will update the ./reducers/stuffReducer.js to import the actions types, and have a nice little case statement of how to handle each type of action. We will also update the ./reducers/rootReducer.js with the necessary plumbing, as well our new fun stuffReducer .
Setting Up The Store:
The redux docs describe the store as the object that brings together the actions and reducers.
Now that we have some action types, and a reducer in out rootReducer, we need to get everything talking to the app. In the ./store/configureStore.js file we will import createStore from redux , and our rootReducer.
We will pass to createStore our middleware ( thunk ), the rootReducer and some arguments to enable the dev tools, which are really nice when working with a redux app.
To use this shiny new code we need to add our store to the Provider . In the index.js file of our little app, we should import Provider from react-redux and have that wrap our app component. This component will now take the store we pass it as a prop, which we have returned from the function we just wrote in configureStore .
At this point we have a lot the the initial set up work set. Of course we will need some components to actually dispatch an action or two, for us to see it all working together.
Writing a Connected Component:
Let’s add a new component that lists all our stuff . For this add a StuffList.js file. Then render this new component inside theApp component.
In addition to everything you are used for React we will also be importing connect from react-redux and bindActionCreators from redux , along with our actions from ./actions/stuffActions.js . Note that bindActionCreators is for when you want to pass some action creators down to a component, and connect used to allow the component access to the redux application state we have implemented.
We will need, in addition to all the normal set up for a fun new react component, two functions that we will ultimately be passing the connect as arguments. These are mapStateToProps and mapDispatchToProps . the first, mapStateToProps will hydrate the props of your component from the state of the application. The next, mapDispatchToProps ensures our actions have access to dispatch from redux.
Once we have all that set up, rather than exporting the class that is this react component itself, we will export the connected component, which is the result of the connect function we imported from react-redux .
Then be sure to import and render our new component in the App .
Using The Dev Tools:
At this point we have everything hooked up. We enabled the dev tools when we configured the store, and so if you are using chrome and have the extension installed we should able to detect our redux store.
After opening the chrome dev tools, look at the new Redux tab! when you load the app you should see a state that matches whatever you have set as your initial state.
You may be thinking “Buy why no stuff?”, this is because we have not dispatched any actions yet!
Triggering an Action:
Back in our StuffList component, we need to tigger an action to fetch our stuff . In this case we can add a componentDidMount function, and inside that call the function fetchStuff .
When, we now load the app, while looking at our redux dev tools, specifically the log monitor, we should see our action logged, and the state being updated.
Woo! Celebrate your new app, and enjoy all the fun you will have with React + Redux.