React is awesome. This is not necessarily an opinion shared by all developers, but it does away with many of the annoyances that we come across when writing vanilla JavaScript. One of the pillars of using React is state. Without going too far down the rabbit hole, state is essentially an object that contains the pieces of an application that can change.
For example, one might use state to show how many likes a particular post or photo received, or one might use state to keep track of the users currently logged in. As an application gets larger, it's quite possible you may have many things that are kept track of in state. This is where Redux comes into play. In a simple application where only a few things exist in state, there is a chance that utilizing Redux could be overkill.
When using React and Redux, it's important to understand the needs of the application you are building. If you only have 2 things to keep track of in state, you might be better off leaving Redux out of the equation. On the other hand, if you have 20 things to be kept in state, and especially if you'll need to access them in different files in your application, Redux might help you make sense of it.
Redux is a state manager, and if you're having trouble imagining how exactly state gets "managed", it gets put in one place, called the store, that can then be accessed throughout your whole application. Implementing Redux does add a bit of complexity to your application, but it may also help simplify it at the same time by keeping your entire state in one place.
The Redux docs themselves outline three principles that dictate its usage. The first is that in Redux, the global state of your application is stored in an object tree within a single store. Second, to specify how the state tree is transformed by actions, you write reducers. And finally, the only way to change the state is to emit an action, an object describing what happened. Let's unpack these three principles.
Creating the Store
The first step in using Redux is using the store. And to use it, we have to import it from redux like so:
import { createStore } from 'redux'
Then we will define a variable store. Unlike other variables where the name is up to the developer, the store must be named store. The next step is putting the function createStore to work. The way that this is done is fairly simple.
const store = createStore(students, ['Liz'])
In this very simple example, we are going to have a store for students, and I'll explain how we will go about adding a student to the store.
Using Reducers
Next up we need to build a reducer that will handle the action we need accomplished. For our purposes, the reducer will look like this:
function students(state = [], action) {
switch(action.type)
case 'ADD_STUDENT'
return state.concat([action.text])
default:
return state
}
}
As is the norm for reducers, we are utilizing a switch statement. The case gives us a description of what we're going to do(the action), and clearly, we are going to add a student by returning stat.concat([action.text]). The default action, return state, is there to be used when our store is left unchanged. So we have a reducer written to add a student to our array, and now we come to the last step, which is to dispatch our action.
Dispatching an Action
The next piece of the redux puzzle is to dispatch our actions. We do this by calling the dispatch method on our store. Our dispatch method will contain an object that contains our action type, as well as the name of the student we are going to add. We'll call the method like this:
store.dispatch({
type: 'ADD_STUDENT',
name: 'Jamie'
})
From here, if we check our state using store.getState(), we will see that Jamie has been added to our store.
console.log(store.getState())
// ['Liz', 'Jamie']
But what if a student graduates or moves away and we need to remove them from our store? We would simply add a 'REMOVE_STUDENT' action to our reducer, and then dispatch it.
function students(state = [], action) {
switch(action.type)
case 'ADD_STUDENT'
return state.concat([action.text])
case 'REMOVE_STUDENT'
const students = state.students.filter(student => student.id !== action.id)
return {
...state,
students
}
default:
return state
}
}
Above we defined the variable students within our action, and then used the spread operator to leave the rest of our state unchanged. From there, we would dispatch as we did to 'ADD_STUDENT'.
We built the store, created a reducer to handle the actions we want done upon our store, and finally we dispatched those actions. I wanted this to be a simple example to explain what each piece of the puzzle accomplishes.
Here are some other great resources regarding how and when to use Redux:
When should I use Redux?
The Redux Toolkit
The Redux Style Guide
A Quick Start Tutorial which uses the Toolkit and hooks to demonstrate the "right way" to write Redux
I hope this helped clarify any questions you might have, and I hope you have fun working with React and Redux!
Top comments (6)
Hi, I'm a Redux maintainer. I'd like to point to a few specific resources that provide additional info:
And finally, I'm currently writing a new "Quick Start" tutorial for the Redux docs, which will serve as a top-down introduction to Redux, showing Redux Toolkit and the React-Redux hooks API as "the right way" to write Redux logic. You can see the WIP preview version of the tutorial here.
Thanks for reaching out! I'll link to these in the post.
To make your code example look better use this:
'''javascript
code goes here.
'''
I've used triple single quote above, replace with backticks ;-)
Great tip, thanks!
Nice!
The useContext hook doesn't support this scenario which you have 20 things to be kept in state, and need to access them in different files in your application?