Shahid Alam
Posted on March 16, 2023
Redux seemed way too complicated (skippable)
Redux a popular tool that's often mentioned in tech Discord groups and numerous job posts. In fact, nowadays if you're familiar with React, it's practically a given that you should also know Redux.
When I decided to learn Redux, I quickly realized that setting it up could be a bit of a headache. I spent hours watching 15-minute-long videos that attempted to explain what a reducer, store, and Redux actually are. But the more I watched, the more confused I became.
After reading a variety of articles, I finally managed to set up a Redux store and begin to understand it. However, I realized that it would be helpful to simplify the process of learning Redux for others. That's why I'm writing this post - to provide a clear and straightforward explanation of Redux Toolkit that anyone can use in their application. If you have any feedback or notice any errors in my code, please don't hesitate to leave a comment below. I'll be sure to address it as soon as possible.
Note - in case you are overwhelmed with my explanation, feel free to copy paste them and then go through the explanation. Be sure to use console.log whenever you want to!
Step 1 - Installing Redux and Redux Toolkit
Simply copy paste and install the following to your React application.
npm install redux @reduxjs/toolkit
Step 2 - Creating a Store
what is store? what is action? what is dispatch?
Store is what it sounds like - a store of reducers and states which can be used throughout the application without the hassle of being passed as props.
For example - if you are building a social media app, you would like the details of the user to be accessed in any component. You can simply do this by "calling" the details in that particular page or component(like setting, profile page,etc.) from the store file.
Now, you would like to manipulate the value of this state according to the user's actions. For example when the user logs out, you want to empty the "user" state/object (let's call this function removeUser). Or populate it with data when user logs in (let's call this function addUser). These are two different functions for two different scenarios for the same object. These types of functions are called Reducers.
Go to your src folder of your React project and create a folder called "redux". In it, create a file called store.jsx (or js if you have created your project using create-react-app) and paste the following code.
src/redux/store.jsx
//configureStore will help us set up our store
import { configureStore } from '@reduxjs/toolkit';
//we are exporting the store by default
//if you want, you can also assign it to a variable and then export it
export default configureStore({
reducer: {}, //all our reducer functions will go here
});
Step 3 - Making our store available throughout the application
Go to index.jsx, index.tsx or main.tsx and paste the following. Depending on whether you have created your react app using create-react-app or vite or any other building tool, this may vary.
We import the Provider wrapper here that helps "distribute" the store we created throughout the application. Then, we pass the store object we created (after importing it of course) as props to it so that it knows which file to be made available globally.
src/App.jsx or src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import store from './redux/store'; // importing the store we created
import { Provider } from 'react-redux';
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
Step 4 - Creating a Slice
Slice file contains a state variable and different functions(reducers) for that particular state, that will become a part of the redux store we previously created. Think of them as files that keep states separately from one another.
For analogy - think of them as rooms of your house. Bedroom - there is bed, your regular furniture and your wardrobe. These are all "states" inside a "slice"(room). You perform various functions(reducers) here - sleep, lay down, cry because your life sucks or simply lay down and watch a movie or two.
src/redux/userSlice.jsx
import { createSlice } from '@reduxjs/toolkit';
//import PayloadAction in case you're using Typescript
import type { PayloadAction } from '@reduxjs/toolkit';
export const userSlice = createSlice({
name : "userInfo",
initialState : {},
reducers:{
//in case of typescript -
//adding the type of payload action(data) we need to pass to this reducer (function).
addUser:(state:any,action:PayloadAction<string>)=>{
const data = {
email: action.payload.email,
password: action.payload.password,
};
//pushing the login data to the state object in this slice
state.push(data);
}
}
})
//keep adding the reducers' names to make them available globally
export const {addUser} = userSlice.actions;
export default userSlice.reducer;
we import the reducers that we exported in the slice and add it to our store
src/redux/store.jsx
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './userSlice';
export default configureStore({
reducer: {
// the "user" key will be used to identify the slice we are dealing with
//in case of multiple slices, we can create different keys for different reducers(of those relevant slices)
user : userReducer,
},
});
Step 4 - Accessing and updating the state inside our slice file/files
Go to the file where you want to add the login data to your store. For this example, we are going to send the email id and password to our userSlice state using useDispatch hook. This hook will allow us to "push" or send our data to the slice state using its reducer(in this case - addUser).
login.tsx
import { useDispatch } from 'react-redux';
import { addUser } from "../../redux/userSlice";
function Login() {
const dispatch = useDispatch();
const handleLogin = () => {
// Perform login logic here, e.g. send login request to server using fetch or axios
// Assuming login is successful, add user to state
const user = { email: "johndoe@example.com", passowrd: "passwordlol" };
dispatch(addUser(user));
}
return (
<div>
<h1>Login Form</h1>
{/* Login form here */}
<button onClick={handleLogin}>Login</button>
</div>
);
}
Now when the user clicks on the Login button, the store will execute the reducer addUser and add the information as a action.payload object to the user state we created in userSlice. You can check the code in step 4 for what we did to the data sent to the slice.
Now, how can we access the data? We simply use the useSelector hook. This hook allows us to access the slices and the states inside them.
dashboard.tsx
import React from 'react';
import { useSelector } from 'react-redux';
const ExampleComponent = () => {
// This hook allows us to extract data from the Redux store state
//notice how we are using the key for accessing the userSlice state given in the store
const email = useSelector((state) => state.user.data.email);
return (
<div>
<h1>Hello {email}!</h1>
</div>
);
};
export default ExampleComponent;
Aaaand that's it! Now all you have to do is add more reducers and import useDisptach or useSelector hook to use the states in the store throughout the application. Easy right?
Feel free to copy paste the code to speed up your development. Let me know in case you encounter any error or if you have any feedback for this article.
See you next time!
Posted on March 16, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.