React Router 未在 URL 中呈现产品 ID

问题描述 投票:0回答:3


您好,我正在我的简单电子商务应用程序中实现 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;
  1. fetcher.js
   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}`)
}
  1. index.js
   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();
  1. 类别产品.js
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

  1. 这是我的db.json
  {
    "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
      }
    ]
  }
  

任何帮助将不胜感激!谢谢!

reactjs react-props
3个回答
0
投票

您似乎在 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}
      />

0
投票
<div className='category-products-title'>
  <Link to={`/products/${productId}`}>. 
    {title}</Link>
  </div>

尝试将 id 更改为productId


0
投票

请为您提供更多背景信息。粘贴整个组件的内容。这可能是一个范围问题,您传递的 id 未在该组件中定义。

我还看到您已将 url 参数定义为产品 id,确保您在 ProductDetail 组件中使用相同的名称访问它。

© www.soinside.com 2019 - 2024. All rights reserved.