
React with Redux From Counter to Shopping Cart
Redux is a powerful tool for managing state in React applications. In this guide, we'll start simple with a basic counter to help you get a grip on Redux's core concepts. Then, we’ll take things up a notch and build a more complex shopping cart application step-by-step.
Understanding Redux with a Simple Counter Example
Before we dive into the shopping cart, let's break down the core ideas of Redux with a simple counter example.
The Counter Example
Imagine a button on the screen. Every time you click it, a number increases. How would you implement this with Redux? Here's how:
Action: This is where we define what happens when something changes.
const INCREMENT = 'INCREMENT';
const incrementAction = () => ({
type: INCREMENT
});
Reducer: It specifies how the state changes in response to the action.
const initialState = { count: 0 };
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case INCREMENT:
return { count: state.count + 1 };
default:
return state;
}
};
Store: This holds the entire state of your application.
import { createStore } from 'redux';
const store = createStore(counterReducer);
Dispatch: It’s how we send actions to update the state.
store.dispatch(incrementAction());
Subscription: This is how components are notified about state updates.
Putting it All Together
Here’s how it looks when everything is combined into a React component:
import React from 'react';
import { createStore } from 'redux';
import { Provider, useSelector, useDispatch } from 'react-redux';
// Action
const INCREMENT = 'INCREMENT';
const incrementAction = () => ({ type: INCREMENT });
// Reducer
const counterReducer = (state = { count: 0 }, action) => {
switch (action.type) {
case INCREMENT:
return { count: state.count + 1 };
default:
return state;
}
};
// Store
const store = createStore(counterReducer);
// React Component
function Counter() {
const count = useSelector(state => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(incrementAction())}>Increment</button>
</div>
);
}
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
export default App;
In this example:
- Action:
incrementActiondefines what happens. - Reducer:
counterReducerexplains how the state should change based on the action. - Store: It holds the state, created using the reducer.
- Dispatch: It sends actions to the store (triggered by the button click).
- useSelector: This is how you access the state in a component.
By understanding these concepts through a simple counter, you’re now ready for the next step: building a shopping cart!
Building a Shopping Cart Application with Redux
1. Project Setup
To kick things off, we need to create a new React project and set up Redux.
1.1. Creating a React Project
Open your terminal and run:
npx create-react-app redux-shopping-cart
cd redux-shopping-cart
This will create a new React project named "redux-shopping-cart" and move you into that project directory.
1.2. Installing Redux and Required Packages
Now, install Redux and its dependencies:
npm install redux react-redux @reduxjs/toolkit
This adds Redux, React-Redux, and Redux Toolkit to your project.
2. Project Structure
Your project structure will look like this:
redux-shopping-cart/
├── public/
│ └── index.html
├── src/
│ ├── components/
│ │ ├── ProductList.js
│ │ └── Cart.js
│ ├── store/
│ │ ├── index.js
│ │ └── cartSlice.js
│ ├── App.js
│ └── index.js
└── package.json
To match this structure, create components and store folders inside src.
3. What is Redux and Why Use It?
Redux helps manage state in complex React applications. When you have a lot of components that need to share or sync data, Redux makes this easier.
4. Basic Redux Concepts Recap
- Store: A central place that holds the state.
- Action: Describes what happened.
- Reducer: Describes how the state changes.
- Dispatch: Sends an action to the store.
5. Shopping Cart Application
Now let’s use these ideas to build a shopping cart.
5.1. Creating the Redux Store
Create a new file src/store/index.js and add:
import { configureStore } from '@reduxjs/toolkit';
import cartReducer from './cartSlice';
const store = configureStore({
reducer: {
cart: cartReducer,
},
});
export default store;
This sets up the store using configureStore from Redux Toolkit, with cartReducer handling cart state.
5.2. Creating a Slice
Redux Toolkit introduces "slices" to keep related actions, reducers, and state together. Create src/store/cartSlice.js:
import { createSlice } from '@reduxjs/toolkit';
const cartSlice = createSlice({
name: 'cart',
initialState: {
items: [],
},
reducers: {
addItem: (state, action) => {
const existingItem = state.items.find(item => item.id === action.payload.id);
if (existingItem) {
existingItem.quantity += 1;
} else {
state.items.push({ ...action.payload, quantity: 1 });
}
},
removeItem: (state, action) => {
state.items = state.items.filter(item => item.id !== action.payload);
},
},
});
export const { addItem, removeItem } = cartSlice.actions;
export default cartSlice.reducer;
This slice sets up initial state and actions to add or remove items.
5.3. Creating React Components
Next, create components to display products and the cart.
In src/components/ProductList.js:
import React from 'react';
import { useDispatch } from 'react-redux';
import { addItem } from '../store/cartSlice';
const products = [
{ id: 1, name: 'Product 1', price: 10 },
{ id: 2, name: 'Product 2', price: 20 },
{ id: 3, name: 'Product 3', price: 30 },
];
function ProductList() {
const dispatch = useDispatch();
return (
<div>
<h2>Products</h2>
<ul>
{products.map(product => (
<li key={product.id}>
{product.name} - ${product.price}
<button onClick={() => dispatch(addItem(product))}>Add to Cart</button>
</li>
))}
</ul>
</div>
);
}
export default ProductList;
This component lists products and adds them to the cart with addItem.
In src/components/Cart.js:
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { removeItem } from '../store/cartSlice';
function Cart() {
const cartItems = useSelector(state => state.cart.items);
const dispatch = useDispatch();
const total = cartItems.reduce((sum, item) => sum + item.price * item.quantity, 0);
return (
<div>
<h2>Cart</h2>
<ul>
{cartItems.map(item => (
<li key={item.id}>
{item.name} - ${item.price} x {item.quantity}
<button onClick={() => dispatch(removeItem(item.id))}>Remove</button>
</li>
))}
</ul>
<p>Total: ${total}</p>
</div>
);
}
export default Cart;
This component displays cart items and removes them with removeItem.
5.4. Main Application Component
Update src/App.js:
import React from 'react';
import ProductList from './components/ProductList';
import Cart from './components/Cart';
function App() {
return (
<div>
<h1>Redux Shopping Cart Example</h1>
<ProductList />
<Cart />
</div>
);
}
export default App;
5.5. Connecting the Redux Store to the React Application
Finally, connect Redux to the app in src/index.js:
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
This connects the Redux store using the Provider.
6. Running the Application
Run npm start in your terminal to see it in action!
7. Conclusion
We’ve gone from a simple counter to a full shopping cart application, showing how Redux scales from basic to more complex scenarios. Redux allows us to manage application state efficiently, especially as the app grows. As you get more comfortable, you’ll find even more powerful features in Redux to handle state in large applications.








