skip to Main Content

I was making small project of react in which I wanted to use "Redux toolkit" for my cart logic.

What I want :

When I will click on button "Add To Bag", it should add ( quantity, color, name, company name etc ) into cart as a 1 item.

And when I will open a Cart page, it should render it.

Here is my Redux code :

Index.js

import { Provider } from "react-redux";
import { store } from "./Redux/Store";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <>
    <Provider store={store}>
      <App />
    </Provider>
  </>
);     

Store.js

import { configureStore } from "@reduxjs/toolkit";
import cartReducer from "./Slices/CartSlices";

export const store = configureStore({
  reducer: {
    cart1: cartReducer,
  },
});

CartSlices.js

import { createSlice } from "@reduxjs/toolkit";

const cartSlice = createSlice({
  name: "Cart",
  initialState: [],
  reducers: {
    addItem: (state, action) => {
      state.push(action.payload);
    },
  },
});
export const { addItem } = cartSlice.actions;
export default cartSlice.reducer;

SingleProduct.js

import React, { useEffect, useState } from "react";
import { Link, useLocation } from "react-router-dom";
import "./SingleProduct.css";
import { addItem } from "../Redux/Slices/CartSlices";
import { useDispatch } from "react-redux";

function SingleProduct() {
  const location = useLocation();
  const productData = location.state?.data;
  const dispatch = useDispatch();

  const [selectedColorIndex, setSelectedColorIndex] = useState(null);
  const [selectedQuantity, setSelectedQuantity] = useState(0);

  const QuantitySelect = () => {
    const options = Array.from({ length: 10 }).map((_, i) => (
      <option key={i} value={i}>
        {i}
      </option>
    ));
    return options;
  };

  return (
    <section>
      <div className="row">
        <div className="col-md-6">
          <img
            src={productData.attributes.image}
            alt=""
            className="mt-5 rounded-5 ms-5 shadow"
            style={{
              objectFit: "cover",
              height: "400px",
              width: "550px",
            }}
          />
        </div>
        <div className="col-md-6 mt-5">
          <h2 className="fw-bold">{productData.attributes.title}</h2>
          <h5 className="fw-bold text-black-50 mt-3">
            {productData.attributes.company}
          </h5>
          <p className="mt-3">
            <span>$</span>
            {productData.attributes.price}
          </p>
          <p className="lead fs-6 fw-light lh-lg">
            {productData.attributes.description}
          </p>
          <div>
            <p className="fw-bold"> Colors</p>
            <div className="d-flex">
              {productData.attributes.colors.map((color, index) => (
                <div
                  key={index}
                  className={`dot ${
                    selectedColorIndex === index ? "selected-dot" : ""
                  }`}
                  style={{ backgroundColor: color }}
                  onClick={() => setSelectedColorIndex(index)}
                ></div>
              ))}
            </div>
            <div>
              <p className="mt-3 fw-bold">Quantity</p>
              <select
                className="form-select w-50 rounded-3"
                value={selectedQuantity}
                onChange={(e) => setSelectedQuantity(e.target.value)}
              >
                <QuantitySelect />
              </select>
            </div>

             {/* <Link to={"/cart"}> */}
              <div
                className="btn mt-4 text-white"
                style={{ backgroundColor: "#463aa1", height: "40px" }}
                onClick={(e) =>
                  dispatch(
                    addItem({
                      image: productData.attributes.image,
                      companyName: productData.attributes.company,
                      price: productData.attributes.price,
                      title: productData.attributes.title,
                      color: selectedColorIndex,
                      quantity: selectedQuantity,
                    })
                  )
                }
              >
                Add To Bag
              </div>
          {/* </Link> */}
          </div>
        </div>
      </div>
      {/* Empty div for space */}
      <div style={{ height: "50px" }}></div>
    </section>
  );
}

export default SingleProduct;

Cart.js

import { useSelector } from "react-redux";
function Cart() {
  const items = useSelector((state) => state);

  console.log("Items : ", items);
  // render code
}

I tried to debug through "Redux dev tool" extension. I found 2 items in the cart. ( which is correct behaviour )

enter image description here

But when I try to print on console ( in cart.js , I tried to print ), I can not see 2 items in the cart.

enter image description here

Where I am making a mistake ?

Observation :

If I redirected to the "/cart" page immediately after clicking the
"Add to Bag" button, ( using Link tag ) then I can see element in the
cart.
But if I redirected to "/cart" page separately, then
above problem appears.

Update :
App.js

import "./App.css";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import {
  About,
  Cart,
  Checkout,
  Error,
  HomeLayout,
  Landing,
  Login,
  Orders,
  Products,
  Register,
  SingleProduct,
} from "./pages";

const router = createBrowserRouter([
  {
    path: "/",
    element: <HomeLayout />,
    errorElement: <Error />,
    children: [
      {
        index: true,
        element: <Landing />,
      },
      {
        path: "products",
        element: <Products />,
      },
      {
        path: "products/:id",
        element: <SingleProduct />,
      },
      {
        path: "cart",
        element: <Cart />,
      },
      {
        path: "about",
        element: <About />,
      },
      {
        path: "checkout",
        element: <Checkout />,
      },
      {
        path: "orders",
        element: <Orders />,
      },
    ],
  },
  {
    path: "/login",
    element: <Login />,
    errorElement: <Error />,
  },
  {
    path: "/register",
    element: <Register />,
    errorElement: <Error />,
  },
]);
function App() {
  return <RouterProvider router={router} />;
}

export default App;

Another Update :
Navbar.jsx

import React, { useEffect, useState } from "react";
import { BsSunFill, BsMoonFill, BsCart3 } from "react-icons/bs";
import { FaBarsStaggered } from "react-icons/fa6";
import { NavLink } from "react-router-dom";
import { NavLinks } from "./NavLinks";
import { useSelector } from "react-redux";

function Navbar() {
  const items = useSelector((state) => state);
  return (
    <nav className="navbar navbar-expand-sm  navbar-clr">
      <div className="container">
        <NavLink
          to="/"
          className=" navbar-brand btn btn-sm fs-6 d-none d-md-block text-white fs-6"
          style={{ background: "#016efe" }}
        >
          C
        </NavLink>
        <button
          class="navbar-toggler"
          type="button"
          data-bs-toggle="collapse"
          data-bs-target="#navbarNav"
          aria-controls="navbarNav"
          aria-expanded="false"
          aria-label="Toggle navigation"
        >
          <span class="navbar-toggler-icon">
            <FaBarsStaggered className="text-white" />
          </span>
        </button>

        <div class="collapse navbar-collapse" id="navbarNav">
          <ul class="navbar-nav mx-auto ">
            <li class="nav-item">
              <a
                class="nav-link active text-black  mx-3"
                aria-current="page"
                href="/"
              >
                Home
              </a>
            </li>
            <li class="nav-item">
              <a class="nav-link text-black mx-3" href="about">
                About
              </a>
            </li>
            <li class="nav-item">
              <a class="nav-link text-black mx-3" href="product">
                Product
              </a>
            </li>
            <li class="nav-item">
              <a
                class="nav-link text-black mx-3 "
                // style={{ background: "#02152c" }}
                href="/cart"
              >
                Cart
              </a>
            </li>
            <li class="nav-item">
              <a class="nav-link text-black mx-3" href="checkout">
                Checkout
              </a>
            </li>
            <li class="nav-item">
              <a class="nav-link text-black mx-3" href="orders">
                Orders
              </a>
            </li>
          </ul>
          {/* <NavLinks /> */}
        </div>

        <NavLink to="/cart" class="position-relative">
          <div>
            <BsCart3
              style={{ height: "30px", width: "30px" }}
              className="text-black"
            />
            <span
              class="position-absolute top-5 start-90 translate-middle badge rounded-pill"
              style={{ background: "#016efe" }}
            >
              {items.cart1.length}
            </span>
          </div>
        </NavLink>
      </div>
    </nav>
  );
}

export default Navbar;

2

Answers


  1. If you are redirecting to your cart page with a refresh then you should use redux-persist to store that data in the user’s local machine, and if you are not getting data while console.logging, try adding this line in your cartSlice.js

    export const cartSelector = state => state.Cart;
    

    and secondly, change cart1 to Cart in Store.js. Always keep the same name in your store.js and slicename like Cart and Cart, not Cart and Cart1.

    import your cartSelector in Cart.js;

    let cartItem = useSelector(cartSelector);
    

    I hope it will help you.

    Login or Signup to reply.
  2. The Navbar component is rendering raw anchor tags that when clicked will result in the page being reloaded and all state, including the Redux store, being reset when the page reloads and the app remounts.

    Instead of raw anchor tags use either the Link or NavLink component(s) from react-router-dom.

    Example:

    import React, { useEffect, useState } from "react";
    import { BsSunFill, BsMoonFill, BsCart3 } from "react-icons/bs";
    import { FaBarsStaggered } from "react-icons/fa6";
    import { NavLink } from "react-router-dom";
    import { NavLinks } from "./NavLinks";
    import { useSelector } from "react-redux";
    
    function Navbar() {
      const items = useSelector((state) => state);
      return (
        <nav className="navbar navbar-expand-sm  navbar-clr">
          <div className="container">
            <NavLink
              to="/"
              className=" navbar-brand btn btn-sm fs-6 d-none d-md-block text-white fs-6"
              style={{ background: "#016efe" }}
            >
              C
            </NavLink>
            <button
              class="navbar-toggler"
              type="button"
              data-bs-toggle="collapse"
              data-bs-target="#navbarNav"
              aria-controls="navbarNav"
              aria-expanded="false"
              aria-label="Toggle navigation"
            >
              <span class="navbar-toggler-icon">
                <FaBarsStaggered className="text-white" />
              </span>
            </button>
    
            <div class="collapse navbar-collapse" id="navbarNav">
              <ul class="navbar-nav mx-auto ">
                <li class="nav-item">
                  <NavLink
                    className="nav-link active text-black  mx-3"
                    aria-current="page"
                    to="/"
                  >
                    Home
                  </NavLink>
                </li>
                <li class="nav-item">
                  <NavLink className="nav-link text-black mx-3" to="/about">
                    About
                  </NavLink>
                </li>
                <li class="nav-item">
                  <NavLink className="nav-link text-black mx-3" to="/product">
                    Product
                  </NavLink>
                </li>
                <li class="nav-item">
                  <NavLink
                    className="nav-link text-black mx-3 "
                    // style={{ background: "#02152c" }}
                    to="/cart"
                  >
                    Cart
                  </NavLink>
                </li>
                <li class="nav-item">
                  <NavLink className="nav-link text-black mx-3" to="/checkout">
                    Checkout
                  </NavLink>
                </li>
                <li class="nav-item">
                  <NavLink className="nav-link text-black mx-3" to="/orders">
                    Orders
                  </NavLink>
                </li>
              </ul>
            </div>
    
            <NavLink to="/cart" class="position-relative">
              <div>
                <BsCart3
                  style={{ height: "30px", width: "30px" }}
                  className="text-black"
                />
                <span
                  class="position-absolute top-5 start-90 translate-middle badge rounded-pill"
                  style={{ background: "#016efe" }}
                >
                  {items.cart1.length}
                </span>
              </div>
            </NavLink>
          </div>
        </nav>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search