Open In App

Wishlist Functionality using Redux Toolkit in React

Last Updated : 21 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Wishlist is one of the important concepts of an E-commerce platform. In this article, we are going to learn how to implement Wishlist functionality using React JS and Redux Toolkit.

Preview of final output: Let us have a look at how the final output will look like.

preview--(1)

Prerequisites

Approach to create Wishlist Functionality:

  • Install Redux Toolkit:Use npm or yarn to install Redux Toolkit: npm install @reduxjs/toolkit or yarn add @reduxjs/toolkit.
  • Create Wishlist Slice:Use createSlice to define a Redux slice for the Wishlist.Specify the initial state and create reducers for actions like addToWishlist and removeFromWishlist.
  • Combine Reducers:Combine the Wishlist reducer with other reducers, if any, using combineReducers.
  • Configure Redux Store:Utilize configureStore to set up the Redux store and pass the combined reducer.
  • Dispatch Actions in Components:Use useDispatch and useSelector hooks from react-redux in components.Dispatch actions (e.g., addToWishlist, removeFromWishlist) based on user interactions.

Steps to Create and Configure React App with redux toolkit

Step 1: Create a react app using command “npx create-react-app app-name”.

npx create-react-app app-name

Step 2: Install the required dependencies

npm install react-redux @reduxjs/toolkit
npm install react-hot-toast
npm i react-router-dom react-icons

Project Structure:

ssps-

The updated dependencies in package.json file will look like:

 "dependencies": {
"@reduxjs/toolkit": "^2.0.1",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
"react-icons": "^4.12.0",
"react-redux": "^9.0.4",
"react-router-dom": "^6.21.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Example: Create the folder structure and insert the following files accordingly.

Javascript




// Wishlist/index.jsx
 
import { useSelector }
    from "react-redux"
import RenderwishlistItems
    from "./RenderWishlistItems"
 
export default function Wishlist() {
    const {total, totalItems} =
        useSelector((state) => state.wishlist)
    return (
        <div >
            <h1>Your wishlist</h1>
            <p >{totalItems} Items in wishlist</p>
            {
                total>0
                ? (
                    <div >
                        <RenderwishlistItems />
                    </div>
                )
                : (
                    <p>Your wishlist is empty</p>
                )
            }
        </div>
    )
}


Javascript




// Wishlist/RenderWishlistItems.jsx
 
import React from 'react'
import { useDispatch, useSelector }
    from 'react-redux'
import {RiDeleteBin6Line}
    from "react-icons/ri"
import { removeFromWishlist } from '../Slices/WishlistSlice' 
 
export default function RenderWishlistItems() {
    const {wishlist} = useSelector((state) => state.wishlist)
    const dispatch = useDispatch();
 
  return (
    <div>
        {
            wishlist.map((dataObj, index) => (
                <div
                    key={index}
                    className=
                        {
                            `flex w-full flex-wrap
                            items-start justify-between gap-6
                        ${index !== wishlist.length - 1 &&
                            "border-b border-b-richblack-400 pb-6"}
                        ${index !== 0 && "mt-6"} `
                    }>
                     <div>
                        <div>
                            {dataObj.title}
                        </div>
                        <img src={dataObj.image}
                            width={200} height={150}
                             alt="" />
                        <p>
                            {dataObj.description}
                        </p>
                     </div>
 
                    <div>
                        <button
                            onClick={
                                () =>
                                    dispatch(removeFromWishlist(dataObj._id))
                            }>
                            Remove from wishlist 
                            <RiDeleteBin6Line size={20}/>
                        </button>
                    </div>
                </div>
            ))
        }
    </div>
  )
}


Javascript




// Components/Product_card.jsx
 
import React from 'react'
import { addToWishlist }
    from '../Slices/WishlistSlice';
import { useDispatch } from 'react-redux';
import { CiHeart } from "react-icons/ci";
 
const Product_card = ({ dataObj }) => {
    const dispatch = useDispatch();
 
    const handleAddToWishlist =
    () => {
        console.log("dispatching add to Wishlist")
        dispatch(addToWishlist(dataObj));
        return;
    }
 
    return (
        <div
            style={{
                display: 'flex',
                flexWrap: 'wrap',
                gap: '70px',
                justifyContent: 'space-around',
                marginTop: '70px'
            }}>
            <div
                style={{
                    width: "15em",
                    backgroundColor: "#35D841",
                    padding: 2,
                    borderRadius: 10,
                    marginBlock: 10,
                }}>
                <p style={{ fontSize: 20, color: 'black' }}>
                    {dataObj.title}
                </p>
                <img src={dataObj.image} alt=""
                    height={200} width={200}
                    style={{
                        borderRadius: "15px",
                    }}/>
                <p>{dataObj.description}</p>
                      
                <CiHeart
                    onClick={handleAddToWishlist}
                    size={35} color='white'/>
                     
            </div>
        </div>
    )
}
 
export default Product_card


Javascript




// Pages/Home.jsx
 
import React,
{ useEffect, useState } from 'react'
import { FaHeart }
    from "react-icons/fa";
import { Link }
    from 'react-router-dom';
import Product_card
    from '../Components/Product_card';
 
const items = [
    {
      "id": 1,
      "title": "GeeksForGeeks bag",
      "price": 109.95,
      "description": "Your perfect pack for everyday use and walks in the forest.",
      "category": "bag",
      "image":
      "rating": {
        "rate": 3.9,
        "count": 120
      }
    },
    {
      "id": 2,
      "title": "GeeksForGeeks tshirt",
      "price": 22.3,
      "description": "Slim-fitting style,black tshirt. From geeksforgeeks",
      "category": "men's clothing",
      "image":
      "rating": {
        "rate": 4.1,
        "count": 259
      },
    },
    {
        "id": 3,
        "title": "GeeksForGeeks bag",
        "price": 109.95,
        "description": "Your perfect pack for everyday use and walks in the forest.",
        "category": "bag",
        "image":
        "rating": {
          "rate": 3.9,
          "count": 120
        }
      },
]
 
const Home = () => {
    return (
        <div>
            <Link to={"/wishlist"}>
                <FaHeart size={40} color="#35D841" />
            </Link>
            <div
                style={{
                    display: 'Flex',
                    justifyContent: 'space-around',
                }}>
                {items.map((dataObj, index) => {
                    return (
                        <Product_card dataObj={dataObj} />
                    )
                })}
            </div>
        </div>
    )
}
 
export default Home


Javascript




// Reducer/index.jsx
 
import { combineReducers } from "@reduxjs/toolkit";
import wishlistReducer from "../Slices/WishlistSlice"
 
const rootReducer = combineReducers({
    wishlist: wishlistReducer,
})
 
export default rootReducer


Javascript




// Slices/WishlistSlice.jsx
 
import { createSlice } from "@reduxjs/toolkit";
import { toast } from "react-hot-toast";
 
const initialState = {
    wishlist: localStorage.getItem("wishlist")
        ? JSON.parse(localStorage.getItem("wishlist"))
        : [],
    total: localStorage.getItem("total")
        ? JSON.parse(localStorage.getItem("total"))
        : 0,
    totalItems: localStorage.getItem("totalItems")
        ? JSON.parse(localStorage.getItem("totalItems"))
        : 0,
}
 
const wishlistSlice = createSlice({
    name: "wishlist",
    initialState,
    reducers: {
        addToWishlist: (state, action) => {
            const item = action.payload
            state.wishlist.push(item)
            state.totalItems++
            state.total += item.price
            localStorage
                .setItem("wishlist", JSON.stringify(state.wishlist))
            localStorage
                .setItem("total", JSON.stringify(state.total))
            localStorage
                .setItem("totalItems", JSON.stringify(state.totalItems))
            toast.success("Item added to wishlist")
        },
         
        removeFromWishlist: (state, action) => {
            const itemId = action.payload
            const index =
                state.wishlist
                    .findIndex(
                        (item) => item._id === itemId)
 
            if (index >= 0) {
                 
                state.totalItems--
                state.total -= state.wishlist[index].price
                state.wishlist.splice(index, 1)
                localStorage
                    .setItem("wishlist", JSON.stringify(state.wishlist))
                localStorage
                    .setItem("total", JSON.stringify(state.total))
                localStorage
                    .setItem("totalItems", JSON.stringify(state.totalItems))
                toast
                    .success("Item removed from wishlist")
            }
        },
    }
})
 
export const
{
addToWishlist, resetWishlist,
removeFromWishlist
} = wishlistSlice.actions
export default wishlistSlice.reducer;


Javascript




// App.js
 
import './App.css';
import { Route, Routes }
    from "react-router-dom";
import Wishlist from "./Wishlist/index"
import Home from "./Pages/Home";
 
function App() {
  return (
    <div className="App">
      <Routes>
        <Route path="/wishlist"
            element={<Wishlist />} />
        <Route path="/" element={<Home />} />
      </Routes>
    </div>
  );
}
 
export default App;


Javascript




// index.js
 
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import rootReducer from './Reducer';
import { Provider } from "react-redux";
import {configureStore} from "@reduxjs/toolkit"
import { BrowserRouter } from 'react-router-dom';
import { Toaster } from 'react-hot-toast';
 
const store = configureStore({
  reducer: rootReducer,
})
 
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <BrowserRouter>
        <App />
        <Toaster/>
      </BrowserRouter>
    </Provider>
  </React.StrictMode>
);
 
reportWebVitals();


CSS




/* App.css */
 
.App {
  text-align: center;
}
 
.App-logo {
  height: 40vmin;
  pointer-events: none;
}
 
@media (prefers-reduced-motion: no-preference) {
  .App-logo {
    animation: App-logo-spin infinite 20s linear;
  }
}
 
.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}
 
.App-link {
  color: #61dafb;
}
 
@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}


CSS




/* index.css */
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
 
code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}


Steps to Run the Application:

npm start

Output: go to this url http://localhost:3000/

React-App---Google-Chrome-2024-01-10-17-32-18



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads