我是反应新手,我正在尝试构建购物车原型。 当我通过单击“添加”按钮将商品添加到购物车时。它应该显示结帐图标 。 当我单击该图标时,它应该显示所有产品。 当我在产品列表页面添加以下行时。我收到以下错误
去结账/turbo_modules/[电子邮件受保护]/dist/umd/react-router-dom.development.js 中出现错误 (801:7) 无法解构“React__namespace.useContext(...)”的属性“basename”,因为它为空。
在下面提供我的小提琴和代码
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import '../App.css';
// import './App.css';
import { Link } from 'react-router-dom'; // Assuming you're using React Router
const ProductListing = () => {
const [products, setProducts] = useState([]);
const [filteredProducts, setFilteredProducts] = useState([]); // State for search results
const [cart, setCart] = useState(() => {
// Load existing cart from localStorage
const storedCart = localStorage.getItem('cart');
return storedCart ? JSON.parse(storedCart) : [];
});
const addToCart = (product) => {
const newCart = [...cart, product];
setCart(newCart);
localStorage.setItem('cart', JSON.stringify(newCart)); // Store updated cart
};
const [error, setError] = useState(null);
const [currentPage, setCurrentPage] = useState(1);
const productsPerPage = 50;
const [searchTerm, setSearchTerm] = useState(''); // Search state
useEffect(() => {
const fetchProducts = async () => {
try {
const response = await axios.get(
'https://jsonplaceholder.typicode.com/photos'
);
setProducts(response.data);
setFilteredProducts(response.data); // Initialize filtered products
} catch (error) {
setError(error);
}
};
fetchProducts();
}, []); // Calculate indices for slicing the array
// Handle search input changes
const handleSearchChange = (event) => {
setSearchTerm(event.target.value);
};
// Perform search filtering when the search term changes
useEffect(() => {
const newFilteredProducts = products.filter((product) =>
product.title.toLowerCase().includes(searchTerm.toLowerCase())
);
setFilteredProducts(newFilteredProducts);
setCurrentPage(1); // Reset pagination when search changes
}, [searchTerm, products]);
// Calculations for pagination (using filteredProducts)
const indexOfLastProduct = currentPage * productsPerPage;
const indexOfFirstProduct = indexOfLastProduct - productsPerPage;
const currentProducts = filteredProducts.slice(
indexOfFirstProduct,
indexOfLastProduct
);
const handlePageChange = (pageNumber) => {
setCurrentPage(pageNumber);
};
const renderPagination = () => {
const pageNumbers = [];
for (let i = 1; i <= Math.ceil(products.length / productsPerPage); i++) {
pageNumbers.push(i);
}
return (
<nav>
<ul className="pagination">
{pageNumbers.map((number) => (
<li
key={number}
className={
currentPage === number ? 'page-item active' : 'page-item'
}
>
<a
onClick={() => handlePageChange(number)}
href="#"
className="page-link"
>
{number}
</a>
</li>
))}
</ul>
</nav>
);
};
return (
<div className="product-container">
<input
type="text"
placeholder="Search..."
value={searchTerm}
onChange={handleSearchChange}
className="search-input"
/>
{error ? (
<p className="error-message">Error fetching products</p>
) : (
<>
{/* Added for pagination container */}
<div className="product-grid">
{currentProducts.map((product) => (
<div className="product-item" key={product.id}>
{/* {product.id} */}
<img
src={product.thumbnailUrl}
alt={product.title}
style={{ width: '50px', marginRight: '10px' }}
className="product-image"
/>
<p className="product-id">{product.id}</p>
<button onClick={() => addToCart(product)}>Add to Cart</button>
</div>
))}
</div>
{renderPagination()}
<Link to="/checkout" className="checkout-button">
Go to Checkout
</Link>
</>
)}
</div>
);
};
export default ProductListing;
您正在路由器外部渲染一个额外的
ProductListing
,因此它渲染的任何链接组件都缺少路由上下文。
export default function App() {
return (
<div>
{/* <ProductListing /> */} // <-- Remove this
<BrowserRouter>
<Routes>
<Route path="/" element={<ProductListing />} /> // <-- Render here
<Route path="/checkout" element={<CheckoutPage />} />
</Routes>
</BrowserRouter>
</div>
);
}