Redux is a state management library for JavaScript applications, commonly used in conjunction with React. It provides a predictable state container, which allows developers to manage the application state in a more organized and efficient way.
As we know, React follows the component-based approach, where the data flows through the components. In fact, the data in React always flows from parent to child components which makes it unidirectional
But what happens when we try to communicate from a non-parent component?
A child component can never pass data back up to the parent component. React does not provide any way for direct component-to-component communication. Even though React has features to support this approach, it is considered to be a poor practice. It is prone to errors and leads to spaghetti code.
This is where React fails to provide a solution and Redux comes into the picture

Redux provides a “store” as a solution to this problem. A store is a place where you can store all your application state together. Now the components can “dispatch” state changes to the store and not directly to the other components. Then the components that need the updates about the state changes can “subscribe” to the store. This is how Redux makes the data flow easier.
Redux Cycle
The Redux cycle is the series of steps that occur when an action is dispatched and the state of the application is updated.
- Dispatching an action: When an event occurs in the application, such as a user clicking a button, an action is dispatched.
- Updating the state: The action is then passed to the reducer function. The reducer function is a pure function that takes the current state of the application and the action as input, and returns a new state object. The reducer function is responsible for updating the state of the application based on the action that was dispatched.
- Once the state has been updated, the store notifies any subscribed UI components that the state has changed. The UI components can then access the new state and re-render as necessary.
Getting Started with Redux
Install the following packages:
npm install @reduxjs/toolkit react-redux
Create Reducers & Actions using createSlice

import { createSlice } from "@reduxjs/toolkit";
const messageSlice= createSlice({
name: 'messageSlice',
initialState: {
message: ''
},
reducers: {
setMessage: (state, action) => {
state.message = action.payload;
},
resetMessage: (state, action) => {
state.message = '';
}
}
})
export default messageSlice.reducer;
export const { setMessage, resetMessage } = messageSlice.actions;
Add Slice Reducers to the Store
A store is a JavaScript object which can hold the application’s state and provide a few helper methods to access the state, dispatch actions and register listeners. The entire state of an application is saved in a single store

import { configureStore } from "@reduxjs/toolkit";
import messageReducer from "./slices/messageSlice";
export default configureStore({
reducer: {
messageReducer
}
})
Add store provider to the App

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
Dispatch actions in Components
Now we can use the React-Redux hooks to let React components interact with the Redux

import React, {useRef} from 'react'
import { useDispatch } from 'react-redux';
import { setMessage } from '../redux/slices/messageSlice';
const Child1 = () => {
const inputRef = useRef(null);
const dispatch = useDispatch();
function handleSubmit(e){
e.preventDefault();
const inputTextValue = inputRef.current.value;
dispatch(setMessage(inputTextValue));
}
return (
<div>
<form>
<input type="text" ref={inputRef}/>
<input type="submit" onClick={handleSubmit} />
</form>
</div>
)
}
export default Child1;
Read state data in components

import React from 'react';
import { useSelector } from 'react-redux';
const Child2 = () => {
const message = useSelector(state => state.messageReducer.message);
return (
<div>The data from child is: {message}</div>
)
}
export default Child2;

Redux DevTools Extension: Click here
Redux Thunk
Redux Thunk is a middleware for Redux. It allows you to write asynchronous logic that interacts with the Redux store. By default, Redux actions are synchronous, which means that they happen immediately when they are dispatched. However, sometimes you need to perform asynchronous tasks, like fetching data from an API, before updating the store. This is where Redux Thunk comes in.
To see visual representation: Click here
Example:

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
export const fetchData = createAsyncThunk("products/fetch", async () => {
const response = await fetch('https://api.escuelajs.co/api/v1/products');
return await response.json();
})
const productSlice = createSlice ({
name: 'productSlice',
initialState: {
products: [],
status: "idle",
error: null,
},
extraReducers: function (builder) {
builder
.addCase(fetchData.pending, (state, action) => {
state.status = "loading";
})
.addCase(fetchData.fulfilled, (state, action) => {
state.products = action.payload;
state.status = "success";
})
.addCase(fetchData.rejected, (state, action) => {
state.status = "failed";
state.error = action.error.message;
})
}
})
export default productSlice.reducer;
export const {loadProducts} = productSlice.actions;
Now, dispatch the async Thunk from Components
import React, {useEffect} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchData } from '../../redux/slices/productSlice';
import SingleProduct from '../singleProduct/SingleProduct';
const ProductList = () => {
const dispatch = useDispatch();
const products = useSelector(state => state.productReducer.products)
const status = useSelector(state => state.productReducer.status)
useEffect(() => {
dispatch(fetchData()) //dispatch to the middleware
}, [])
if(status === 'loading'){
return <h2 className='loading'>Loading...</h2>
}
if(status === 'failed'){
return <h2 className='loading'>Uh oh! Something went wrong</h2>
}
return (
<div className="productList">
{products.map((item) => (<SingleProduct key={item.id} product={item} />))}
</div>
)
}
export default ProductList;
In conclusion, Redux is a JavaScript state management library that provides a predictable way to manage the state of an application. Redux works by providing a centralized store that stores the entire state of the application, and a series of reducers that process actions to update the state of the application. By using a predictable cycle of dispatching actions, updating the state, and notifying the UI, Redux provides a clear separation between the state and the UI, making it easier to reason about the state of the application and to maintain a consistent state throughout the application.
Check our other articles: https://satyam-arya.click/understanding-react-hooks/