Search code examples
javascriptreactjsreduxreact-reduxredux-toolkit

Not able to see the items in the cart using "redux toolkit"


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;

Solution

  • 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>
      );
    }