Я делал небольшой проект реагирования, в котором хотел использовать «Инструментарий Redux» для логики своей корзины.
Что я хочу :
Когда я нажму кнопку «Добавить в корзину», она должна добавить (количество, цвет, имя, название компании и т. д.) в корзину как 1 товар.
И когда я открою страницу корзины, она должна ее отобразить.
Вот мой код Redux:
Индекс.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>
</>
);
Магазин.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;
Карт.js
import { useSelector } from "react-redux";
function Cart() {
const items = useSelector((state) => state);
console.info("Items : ", items);
// render code
}
Я пытался выполнить отладку с помощью расширения «Инструмент разработчика Redux». Я нашел в корзине 2 товара. (это правильное поведение)
Но когда я пытаюсь распечатать на консоли (в cart.js я пытался распечатать), я не вижу в корзине 2 товара.
Где я делаю ошибку?
Наблюдение:
Если бы я перенаправился на страницу «/cart» сразу после нажатия кнопки Кнопка «Добавить в корзину» (с помощью тега «Ссылка»), после чего я вижу элемент в тележка.
Но если я перенаправлю на страницу «/cart» отдельно, то появляется вышеуказанная проблема.
Обновление :
Приложение.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;
Еще одно обновление: Навбар.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;
🤔 А знаете ли вы, что...
JavaScript обеспечивает обработку ошибок с использованием конструкции try...catch.
Если вы перенаправляете на страницу корзины с обновлением, вам следует использовать redux-persist для хранения этих данных на локальном компьютере пользователя, и если вы не получаете данные во время console.infoging, попробуйте добавить эту строку в свой cartSlice.js
export const cartSelector = state => state.Cart;
и во-вторых, измените корзину1 на Корзину в Store.js
. Всегда сохраняйте одно и то же имя в своем store.js и имя фрагмента, например Cart и Cart, а не Cart и Cart1.
импортируйте свой cartSelector
в Cart.js;
let cartItem = useSelector(cartSelector);
Я надеюсь, что это поможет вам.
Компонент Navbar
отображает необработанные теги привязки, при нажатии на которые страница перезагружается, а все состояние, включая хранилище Redux, сбрасывается при перезагрузке страницы и перемонтировании приложения.
Вместо необработанных тегов привязки используйте компонент(ы) Link
или NavLink
из react-router-dom
.
Пример:
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>
);
}