Getting Started with Redux | React Tutorial
A beginner guide for using redux, a state management library
What is Redux?
Redux is a predictable state container for JavaScript applications, not limited to React, you see? It provides a centralized and predictable way to manage the state of an application, making it easier to track and update data as it flows through different components. Redux follows the principles of a Flux architecture, emphasizing a single source of truth and immutability. By maintaining a global store and using reducers to handle state changes, Redux helps simplify complex data flows, improve debugging capabilities, and facilitate efficient application development.
Learning by building
What are we going to build?
A simple counter app that displays the count value & a functionality to update the value of the count.
We are going to learn how to access the state value stored by redux (where we will see how selector work in action) in the first section & then move on to some state updating section (where we will increase or decrease the value of count using a button where we will see dispatch in action).
Requirements:
JavaScript: A solid understanding of JavaScript fundamentals, including variables, functions, objects, arrays, and ES6 features.
React: Familiarity with React basics, such as components, state, props, and lifecycle methods.
State Management: Understanding the basics of managing application state, including the concept of unidirectional data flow.
Flux Architecture: A high-level understanding of the Flux architecture pattern, which Redux is based on. (Not really required for this tutorial, but nice to have)
Asynchronous JavaScript: Knowledge of asynchronous JavaScript concepts, such as Promises and async/await. (Not really required for this tutorial)
Installation
Open command prompt & navigate to a directory where you want to create the project
Starting a react app with create react app
npx create-react-app counterapp
cd counterapp
Now let’s install the redux packages required
npm install @reduxjs/toolkit
npm install react-redux
That’s it. Now you are ready to use redux in your react app.
Just type
npm start
in command prompt
Section I: Store, Slice, Accessing the state value
Let’s start right away.
I don’t know about you, but I like to clear the src folder altogether since most of them are not required.
Creating the index.js & app.js file
Create a file called index.js inside src folder & paste the following
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import store from './app/store';
ReactDOM.createRoot(document.getElementById('root')).render(
<Provider store={store} >
<App />
</Provider>
);
Explanation: The
Provider
component wraps theApp
component, enabling access to the Redux store throughout the application. It takes astore
prop, which should be the Redux store instance.
Create another file called App.js inside src folder & insert
import Counter from "./components/Counter"; export default function App() { return ( <Counter /> ); }
Here onward, things get a little bit tricky, if you are new to redux. Concepts like store, slice, selector & dispatch might confuse you. It takes time, you should really see how everything is working at each and every step.
Creating the store
In Redux, the store is a core concept that serves as a centralized container for holding the application state. It is the single source of truth for the entire application's data. The store manages the state and provides methods to interact with and update it.
Create a folder called app inside the src directory & inside the app directory, create a file called store.js & insert
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../components/counterSlice'
export default configureStore({
reducer: {
counter : counterReducer
}
})
Explanation: We are creating and exporting a Redux store using the
configureStore
function from the@reduxjs/toolkit
library. The reducer ‘counterReducer’ is not exported yet from the slice, but we will get to that soon.
Creating a slice
In Redux, a slice is a concept introduced by Redux Toolkit (a set of utilities for Redux) that helps organize and encapsulate related parts of the state, along with the corresponding reducers and actions.
Create a folder called components inside the src directory & inside that, create a file called counterSlice.js & insert
import { createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
}
})
export default counterSlice.reducer
Explanation: A slice requires a unique name in string in order to identify them. We can set the initial state value and reducers inside the slice, but here, we haven’t set any reducers which we will set soon while updating the count.
Creating our component to see the result
Create another file called Counter.js inside the component folder & insert
import React from 'react'
import { useSelector } from 'react-redux'
const Counter = () => {
const count = useSelector(state => state.counter.value)
return (
<div>
<p>Count: {count}</p>
</div>
)
}
export default Counter
Explanation: The
useSelector
hook is used to select and extract thevalue
property from thecounter
slice of the Redux store state. It subscribes the component to updates of that specific state slice.
Output
Count: 0
Section II: Reducers & useDispatch
Now that we have understood how to access the state value stored in the redux store, let’s move onto how to update the state with the use of reducers & useDispatch hook.
Defining the reducers
Modify counterSlice.js to look like this
import { createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
increment: state => {state.value += 1},
decrement: state => {state.value -= 1},
}
})
export const {increment, decrement} = counterSlice.actions
export default counterSlice.reducer
Explanation: Here, we declared two reducers ‘increment’ & ‘decrement’ that simply returns the updated state value by increasing or decreasing the past state. Also, see that the reducers are exported as actions, because they are the actions that the useDispatch hook requires in order to update the state.
Using useDispatch() hook
Also, modify the Counter.js file
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'
import './counter.css'
const Counter = () => {
const count = useSelector(state => state.counter.value)
const dispatch = useDispatch()
return (
<div className='box' >
<p className='count'><span>Count: </span>{count}</p>
<div className=' btn ' >
<button onClick={() => dispatch(increment())} >Add</button>
<button onClick={() => dispatch(decrement())} >Subtract</button>
</div>
</div>
)
}
export default Counter
Explanation: Here, we used useDispatch hook to handle the event. And also, I have put on some basic styles. All the code till now along with the style file can be found in my GitHub repo here.
The result should look like this.
Conclusion
By following this step-by-step guide, you should have gained a solid understanding of Redux concepts, including the store, slices, actions, reducers, and connecting Redux with React components. You should be able to apply this knowledge to build more complex Redux-powered applications and efficiently manage state across their projects.
Remember, Redux is a powerful tool for state management, providing predictability, centralized state, and powerful developer tools. It may introduce some additional complexity initially, but once mastered, it can greatly enhance the maintainability and scalability of JavaScript applications.