Create a Shopping Cart in React with Redux Toolkit Part 1
In this tutorial we are going to create a shopping cart in react with redux toolkit, redux toolkit is the recommended way of managing state since it includes a lot of packages that can be used in any application.
Packages we need
I assume that you have already created a react application, all the packages you need are in the JSON file below.
{
"name": "react-shopping-cart",
"version": "0.1.0",
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.8.6",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.2.0",
"@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.1.3",
"bootstrap-icons": "^1.8.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-redux": "^8.0.4",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"sweetalert2": "^11.4.13",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Create cartSlice
The structure of our application will be like this:
> src > components > features > store
inside features, we add a new file cartSlice.js:
import { createSlice } from "@reduxjs/toolkit";
import Swal from 'sweetalert2';
const initialState = {
cartItems: []
}
export const cartSlice = createSlice({
name: 'cart',
initialState,
reducers: {
addToCart(state, action){
console.log(action);
const item = action.payload;
let productItem = state.cartItems.find(product => product.id === item.id);
if(productItem){
productItem.quantity += 1;
Swal.fire({
position: 'top-end',
icon: 'success',
title: 'Your item has been updated',
showConfirmButton: false,
timer: 1500
});
}else{
state.cartItems = [item,...state.cartItems];
Swal.fire({
position: 'top-end',
icon: 'success',
title: 'Your item has been saved',
showConfirmButton: false,
timer: 1500
});
}
},
incrementQ(state, action){
const item = action.payload;
let productItem = state.cartItems.find(product => product.id === item.id);
if(productItem){
productItem.quantity += 1;
Swal.fire({
position: 'top-end',
icon: 'success',
title: 'Your item has been updated',
showConfirmButton: false,
timer: 1500
});
}
},
decrementQ(state, action){
const item = action.payload;
let productItem = state.cartItems.find(product => product.id === item.id);
if(productItem){
productItem.quantity -= 1;
if(productItem.quantity === 0){
state.cartItems = state.cartItems.filter(product => product.id !== item.id);
}
Swal.fire({
position: 'top-end',
icon: 'success',
title: 'Your item has been updated',
showConfirmButton: false,
timer: 1500
});
}
},
removeFromCart(state, action){
const item = action.payload;
state.cartItems = state.cartItems.filter(product => product.id !== item.id);
Swal.fire({
position: 'top-end',
icon: 'success',
title: 'Your item has been removed',
showConfirmButton: false,
timer: 1500
});
}
}
});
export const { addToCart, incrementQ, decrementQ, removeFromCart } = cartSlice.actions;
export default cartSlice.reducer;
Create productSlice
Inside the same folder (features), we add a new file productSlice.js.
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
products: [
{
id: 1,
name: 'Iphone 12',
price: 700,
image: 'https://cdn.pixabay.com/photo/2016/11/20/08/33/camera-1842202__480.jpg'
},
{
id: 2,
name: 'Samsung s10',
price: 400,
image: 'https://cdn.pixabay.com/photo/2016/03/27/19/43/samsung-1283938__340.jpg'
},
{
id: 3,
name: 'Samsung Tv',
price: 1200,
image: 'https://cdn.pixabay.com/photo/2019/06/30/18/19/tv-4308538__480.jpg'
},
{
id: 4,
name: 'Huwawei Mate',
price: 900,
image: 'https://cdn.pixabay.com/photo/2017/08/11/14/19/honor-2631271__340.jpg'
}
]
}
export const productSlice = createSlice({
name: 'product',
initialState,
reducers: {
}
});
export default productSlice.reducer;
Create store
Inside src/store, we add a new file index.js.
import { configureStore } from '@reduxjs/toolkit';
import cartReducer from '../components/features/cartSlice';
import productReducer from '../components/features/productSlice';
const store = configureStore({
reducer: {
cart: cartReducer,
product: productReducer,
}
});
export default store;
Update index.js
Inside the root folder, we update the index file we add the routes, the store, and the bootstrap 5 styles.
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap-icons/font/bootstrap-icons.css';
import { BrowserRouter } from "react-router-dom";
import store from './store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</React.StrictMode>
);