您好,我正在我的简单电子商务应用程序中实现 React Router。在学习过程中,我遇到了一个问题,希望得到一些帮助。
我使用以下代码成功从 db.json 获取数据:
useEffect(() => {
const fetchData = async () => {
const responseObject = await getCategories();
setCategories(responseObject);
}
fetchData();
}, []);
'getCategories'函数从数据库中检索数据并将其设置为状态,这部分工作完美。
接下来,我实现了产品的获取,效果也很好:
export const getProducts = (id) => {
return fetcher(`/products?catId=${id}`)
}
现在,问题出现在路由上。这是我的 React Router 的实现:
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path='basket' element={<Basket />} />
<Route path='checkout' element={<Checkout />} />
<Route path="products/:productId" element={<ProductDetail />} />
</Routes>
</BrowserRouter>
</React.StrictMode>
路由本身可以完美地往返于每个组件。然而,主要问题在于我用来链接应用程序中各个组件的“链接到”挂钩,特别是因为我使用产品的特定 ID 从 JSON 中获取产品:
<div className='category-products-title'>
<Link to={`/products/${id}`}>{title}</Link>
</div>
链接到路由指向http://localhost:3000/products/undefined,而不是呈现实际的产品 ID。我尝试查询数据库,并且提取按预期工作。我预计点击链接后,页面会根据 ID 路由到实际产品。
这是所有组件的代码。
1.App.js
import React, { useState, useEffect } from 'react';
import './App.css';
import Category from './components/category';
import { getCategories, getProducts } from './fetcher';
import CategoryProduct from './components/categoryProduct';
function App() {
const [categories, setCategories] = useState({ errorMessage: '', data: [] });
const [products, setProducts] = useState({ errorMessage: '', data: [] });
useEffect(() => {
const fetchData = async () => {
const responseObject = await getCategories();
setCategories(responseObject);
}
fetchData();
}, []);
const handleCategoryClick = async (id) => {
const responseObject = await getProducts(id);
setProducts(responseObject);
}
const renderCategories = () => {
return categories.data.map(c =>
<Category
key={c.id}
id={c.id}
title={c.title}
onCategoryClick={() => handleCategoryClick(c.id)}
/>
)
}
const renderProducts = () => {
return products.data.map(p =>
<CategoryProduct
key={p.id}
title={p.title}
image={p.image}
specs={p.specs}
features={p.features}
price={p.price}
stock={p.stock}
/>
);
}
return (
<>
<header>My Simple Web App</header>
<section>
<nav>
{categories.errorMessage && <div>Error: {categories.errorMessage}</div> }
{categories && renderCategories()}
</nav>
<article>
<h1>Products</h1>
{products.errorMessage && <div>Error: {products.errorMessage}</div>}
{products && renderProducts()}
</article>
</section>
<footer>
footer
</footer>
</>
);
}
export default App;
const BASE_URL = "http://localhost:3001"
const fetcher = async (url, id = null) => {
let responseObject = { errorMessage: '', data: [] }
try {
const response = await fetch(BASE_URL + url)
if (!response.ok) {
throw new Error(`HTTP Error ${response.status}`);
}
const responseData = await response.json()
responseObject.errorMessage = ''
responseObject.data = responseData
}
catch (err) {
responseObject.errorMessage = err.message
}
return responseObject
}
export const getCategories = () => {
return fetcher("/categories")
}
export const getProducts = (id) => {
return fetcher(`/products?catId=${id}`)
}
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import ProductDetail from './components/productDetail'
import Checkout from './components/checkout'
import Basket from './components/basket'
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path='basket' element={<Basket />} />
<Route path='checkout' element={<Checkout />}/>
<Route path="products/:productId" element={<ProductDetail />} />
</Routes>
</BrowserRouter>
</React.StrictMode>
);
reportWebVitals();
import React from 'react'
import { Link } from 'react-router-dom'
const CategoryProduct = ({id, title, image, specs, features, price, stock, dimensions}) => {
return (
<main>
<div className='category-products-title'>
<Link to={`/products/${id}`}>{title}</Link>
</div>
<figure>
<div className='category-product-image-container'>
<img src={`/category-images/${title}/${image}`} alt='product_image' />
</div>
</figure>
<aside className='category-product-details'>
<div className='category-product-info-dimensions'>
<h3>Dimensions</h3>
<label>{ specs.dimensions}</label>
</div>
{specs.capacity &&
<div className='category-product-info-capacity'>
<h3>Capacity</h3>
<label>{ specs.capacity}</label>
</div>
}
<div className='category-product-info-features'>
<h3>features</h3>
<ul>
{features?.map((f, i) => {
return <li key={`feature${i}`}>{f}</li>
})}
</ul>
</div>
</aside>
<aside className='category-product-finance'>
<div className='category-product-finance-price'>
$pound;(price)
</div>
<div className='category-product-info-stock'>
<label>Stock Level: {stock}</label>
<label>Free delivery</label>
</div>
<div className='category-product-action'>
<button>View Product</button>
<button>Add to basket</button>
</div>
</aside>
</main>
)
}
export default CategoryProduct
{
"categories": [
{ "id": 1, "title": "Fridges"},
{ "id": 2, "title": "Kettles"},
{ "id": 3, "title": "Televisions"},
{ "id": 4, "title": "Microwaves"},
{ "id": 5, "title": "Laptops"}
],
"products": [
{
"id": 1,
"catId": 1,
"title": "Beko White Fridge Freezer",
"price": 399.99,
"image": "Beko_white_fridge.jpg",
"specs": {
"dimensions": "180x70x60 cm",
"capacity": "300 liters"
},
"stock": 10
},
{
"id": 2,
"catId": 1,
"title": "Whirlpool White Fridge Freezer",
"price": 449.99,
"image": "whirlpool_fridge.jpg",
"specs": {
"dimensions": "175x75x65 cm",
"capacity": "350 liters"
},
"stock": 15
},
{
"id": 3,
"catId": 2,
"title": "Electric Kettle",
"price": 29.99,
"specs": {
"dimensions": "20x20x15 cm"
},
"stock": 20
},
{
"id": 4,
"catId": 2,
"title": "Stainless Steel Kettle",
"price": 39.99,
"specs": {
"dimensions": "25x25x20 cm"
},
"stock": 25
},
{
"id": 5,
"catId": 3,
"title": "Samsung 55 inch 4K TV",
"price": 799.99,
"specs": {
"dimensions": "125x80x10 cm"
},
"stock": 5
},
{
"id": 6,
"catId": 3,
"title": "Sony 65 inch OLED TV",
"price": 1499.99,
"specs": {
"dimensions": "140x85x5 cm"
},
"stock": 3
},
{
"id": 7,
"catId": 4,
"title": "Countertop Microwave",
"price": 99.99,
"specs": {
"dimensions": "50x40x30 cm"
},
"stock": 8
},
{
"id": 8,
"catId": 4,
"title": "Over-the-Range Microwave",
"price": 249.99,
"specs": {
"dimensions": "75x60x40 cm"
},
"stock": 12
},
{
"id": 9,
"catId": 5,
"title": "HP 15.6 inch Laptop",
"price": 899.99,
"specs": {
"dimensions": "38x25x2 cm"
},
"stock": 7
},
{
"id": 10,
"catId": 5,
"title": "Dell XPS 13 inch Laptop",
"price": 1299.99,
"specs": {
"dimensions": "30x20x1 cm"
},
"stock": 4
}
]
}
任何帮助将不胜感激!谢谢!
您似乎在 CategoryProduct 组件中使用 id 属性,但没有将其传递给 App 文件中的该组件。
改变
<CategoryProduct
key={p.id}
title={p.title}
image={p.image}
specs={p.specs}
features={p.features}
price={p.price}
stock={p.stock}
/>
到
<CategoryProduct
id={p.id}
key={p.id}
title={p.title}
image={p.image}
specs={p.specs}
features={p.features}
price={p.price}
stock={p.stock}
/>
<div className='category-products-title'>
<Link to={`/products/${productId}`}>.
{title}</Link>
</div>
尝试将 id 更改为productId
请为您提供更多背景信息。粘贴整个组件的内容。这可能是一个范围问题,您传递的 id 未在该组件中定义。
我还看到您已将 url 参数定义为产品 id,确保您在 ProductDetail 组件中使用相同的名称访问它。