Redux: The Basics, with React
So you can sit back, and just redux.
Utilizing the Redux library in your application can save some major headaches. Redux creates a centrally located store
(think of it as a container) that keeps train of your application’s state
. This can make things much easier when it comes to developing and debugging.
1. Install both packages:
npm install redux
npm install react-redux
2. Set Up The Store:
The function createStore()
is included with the Redux library. It returns an instance of the Redux store when it is invoked. Import the function from redux
and include it in your index.js
file, which is where your ReactDOM
renders if you used create-react-app
to initially build your application.
Then, set a variable equal to the createStore()
function and pass through your reducer functions. (Make sure you import those as well!). Best practice is to wrap your entire <App/>
inside of a Provider
component (also imported, this time from react-redux
) so that we don’t have to pass store
down through props to our App
component. Provider
is key in making the Redux store available throughout our application. It also notifies our Redux app that there has been a state change, thus re-rendering the React app. Once you’re finished, it should look something like the following:
I’ll get to thunk
and applyMiddleware
a bit later!
3. Connect to the Store.
Now for the neat part. Anywhere in your application a component can access the global state. You simply have to import:import { connect } from ‘react-redux’
You then invoke this function where your Component
is exported, because when the entire function is imported elsewhere, you want it imported with this connection in tact.
export default connect(firstArg, secondArg)(ComponentName)
connect()
takes in two arguments, and you’ll often see them aptly named mapStateToProps
and mapDispatchToProps
The first argument, whether you call it mapStateToProps
or not, will always receive the state
as an argument. So whatever you have loaded up into your store via your reducer will show up here. This function, should return an object that, in turn, your component will have access to as props.
Similarly, the second function always receives dispatch()
an argument. So you can link up your reducers directly to components to dispatch actions that update state. The key on the left side of the colon can be named anything, but it’s convention to name them the same. They are only labeled differently below to distinguish the difference. Remember to import reducer functions you plan to pass to your components, and send to dispatch()
.
When writing mapDispatchToProps
the key for your component’s props is the name of the function with a value set to the definition of a function that invokes dispatch. When written like below, in your component you could write this.props.fetchSomething()
and because of Redux what is actually happening is this.props.dispatch(fetchSomething())
.
const mapStateToProps = state => {
return {
keyName: state.keyName
}const mapDispatchToProps = dispatch => {
return {
reducerFunctionKey: () => dispatch(reducerFunction())
}export default connect(mapStateToProps, mapDispatchToProps)(ComponentName)//using destructuringexport default connect(null, {reducerFunction})(ComponentName)// if passing arguments, remember to include them in your function definition this.props.reducerFunction(someArg) //called in component somewhereconst mapDispatchToProps = dispatch => {
return {
reducerFunction: (someArg) => dispatch(reducerFunction(someArg))
}
Keep in mind when you are passing in arguments to a reducer function, include the argument in your function definition, as written above. It may seem silly to mention, however! I came across quite a few colleagues with undefined
props who could not figure out what went wrong and it was simply a minor error in forgetting to map the argument along with dispatch.
Note: If there is not a second argument, dispatch
is automatically sent to props along with mapStateToProps
if you care to dispatch an action directly from your component.
If you have no need to mapStateToProps
it’s important that you pass null
in as your first argument, otherwise you won’t get access to dispatch
as an argument.
3. Quick note on Thunk
Thunk
allows us to return a function inside of our action (which normally returns a JavaScript object). This can be helpful when making fetch requests so that an action dispatches in the correct order. To implement, redux-thunk
must be installed. This can be done via npm install --save redux-thunk
.
Import our new additions:
// /index.jsimport thunk from 'redux-thunk
import { createStore, applyMiddleware } from 'redux'
As seen above, include thunk
in your createStore()
function and you’re all set! Now in your reducer, you will have access to dispatch()
as seen in the following from my application. A function was returned, with an argument of dispatch
that was invoked with the acton {type: 'LOADING_TRAINING_PROGRAMS'}
, once the fetch returns a promise a second dispatch
is sent containing the action’s payload.
I’m still new to this world of developing and welcome any feedback! While building my own React application, I thought it would have been helpful for a quick checklist for all the pieces necessary to incorporate Redux
— so I hope it can be of help to someone else!