You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React路由异常:所有页面被错误重定向至/product/:id页面

React路由重定向异常问题
  • 现象:访问任意URL(包括http://localhost:3000/)都会错误跳转到http://localhost:3000/product/<productID>;访问http://localhost:3000/products/women本应展示women分类商品列表,实际跳转到错误路径。
  • 排查指向:components/Product.jsx中的Navigate组件为问题根源。

App.jsx(路由配置)

import React from 'react'
import Cart from './pages/Cart'
import Home from './pages/Home'
import Login from './pages/Login'
import Product from './pages/Product'
import ProductList from './pages/ProductList'
import Register from './pages/Register'
import { BrowserRouter as Router, Navigate, Route, Routes } from "react-router-dom";
const App = () => {
  const user = true;
  return (
    <Router>
      <Routes>
        <Route exact path="/"  element={<Home />} />
        <Route exact path="/products/:category" element={<ProductList />} />
        <Route exact path="/product/:id" element={<Product />} />
        <Route exact path="/cart" element={<Cart />} />
        <Route exact path="/register" element={user ? <Navigate to="/" /> : <Register />} />
        <Route exact path="/login" element={user ? <Navigate to="/" /> : <Login />} />
      </Routes>
    </Router>
  )
}
export default App

Product.jsx(商品列表组件)

import React from 'react'
import { useEffect, useState } from 'react';
import Product from './Product';
import axios from "axios"
const Products = ({ cate, filters, sort }) => {
  console.log(cate, filters, sort)
  const [products, setProducts] = useState([]);
  const [filteredProducts, setFilteredProducts] = useState([]);
  useEffect(() => {
    const getProducts = () => {
      const res = axios.get(
        cate ? `http://localhost:8000/api/products?category=${cate}`
          : "http://localhost:8000/api/products")
        .then(
          function (res) {
            setProducts(res.data);
            console.log(res)
          }
        ).catch(
          function (err) {
            console.log(err)
          });
    }
    getProducts();
  }, [cate]);
  useEffect(() => {
    cate && setFilteredProducts(
      products.filter((item) => (
        Object.entries(filters).every(([key, value]) => {
          return item[key].includes(value);
        }
        )
      ))
    )
  }, [products, cate, filters])
  useEffect(() => {
    if ((sort === "newest")) {
      setFilteredProducts((prev) =>
        [...prev].sort((a, b) => a.createdAt.localeCompare(b.createdAt))
      )
    } else if (sort === "asc") {
      setFilteredProducts((prev) =>
        [...prev].sort((a, b) => a.price - b.price)
      )
    } else {
      setFilteredProducts((prev) =>
        [...prev].sort((a, b) => b.price - a.price)
      )
    }
  },[sort])
  return (
    <Container >
        {cate
        ? filteredProducts.map((item) => (
          <Product item={item} key={item._id} />))
        : products.slice(0, 8).map((item) => <Product item={item} key={item._id} />)}
    </Container>
  );
};

pages/Product.jsx(商品详情页)

import { useLocation } from 'react-router-dom'
import { useState, useEffect } from 'react';
import { publicRequest } from './requestMethods';
const Product = () => {
   // 返回路径
    const location = useLocation();
    const id = location.pathname.split("/")[2];
    const [product, setProduct] = useState({});
    useEffect(() => {
        const getProduct = async () => {
            try {
                const res = await publicRequest.get("/product/find/" + id);
                setProduct(res.data);
            }
            catch { }
}
        getProduct();
    }, [id])

ProductList.jsx(商品列表页)

import React from 'react'
import { mobile } from './../responsive'
import { useLocation } from 'react-router-dom';
import { useState } from 'react';


const ProductList = () => {

    // 返回路径
    const location = useLocation();
    const cate = location.pathname.split("/")[2];
    console.log(location);
    // 设置selector的值,并返回
    const [filters, setFilters] = useState({});
    const [sort, setSort] = useState("newest");

    const handleFilters = (e) => {

        const value = e.target.value;
        setFilters({
            ...filters,
            [e.target.name]: value,
        });
    };
    console.log(filters)

    return (
        <Container>
            <Navbar />
            <Announcement />
            <Title>Dresses</Title>

            <FilterContainer>
                <Filter><FilterText>Filter Products:</FilterText>
                    <Select name="color" onChange={handleFilters}>
                        <Option disabled>Color</Option>
                        <Option>black</Option>
                        <Option>white</Option>
                        <Option>green</Option>
                        <Option>wheat</Option>
                        <Option>black</Option>
                        <Option>red</Option>
                        <Option>blue</Option>

                    </Select>
                    <Select name="size" onChange={handleFilters}>
                        <Option disabled>Size</Option>
                        <Option>XS</Option>
                        <Option>S</Option>
                        <Option>M</Option>
                        <Option>L</Option>
                        <Option>XL</Option>

                    </Select></Filter>
                <Filter><FilterText>Sort Products:
                    <Select onChange={(e) => setSort(e.target.value)}>
                        <Option value="newest">Newest</Option>
                        <Option value="asc">Price(asc)</Option>
                        <Option value="desc">Price(desc)</Option>


                    </Select></FilterText></Filter>

            </FilterContainer>
            <Products cate={cate} filters={filters} sort={sort} />
            <NewsLetter />
            <Footer />

        </Container>
    )
}

components/Product.jsx(商品卡片组件)

const Product = ({ item }) => {
  return (
    <Container className='container product'>
      <Circle />
      <Img src={item.img} />

      <Info >
        <Icon >
          <ShoppingCartOutlinedIcon />
        </Icon>
        <Icon>
          <Navigate to={`/product/${item._id}`}>
          <SearchOutlinedIcon />
          </Navigate>
        </Icon>
        <Icon>
          <FavoriteBorderOutlinedIcon />
        </Icon>
      </Info>
    </Container>
  )
}

问题根源与修复方案

问题出在components/Product.jsx的Navigate组件使用方式错误:React Router v6中,Navigate是渲染时立即触发重定向的组件,并非用于包裹点击元素的导航容器。当前写法会导致组件一渲染就执行重定向,而非点击图标时才跳转。

修复方式1:使用Link组件(推荐的声明式导航)

import { Link } from 'react-router-dom';
// 导入其他必要组件(如Icon、SearchOutlinedIcon等)
const Product = ({ item }) => {
  return (
    <Container className='container product'>
      <Circle />
      <Img src={item.img} />

      <Info >
        <Icon >
          <ShoppingCartOutlinedIcon />
        </Icon>
        <Icon>
          <Link to={`/product/${item._id}`}>
            <SearchOutlinedIcon />
          </Link>
        </Icon>
        <Icon>
          <FavoriteBorderOutlinedIcon />
        </Icon>
      </Info>
    </Container>
  )
}

修复方式2:使用useNavigate钩子(命令式导航)

import { useNavigate } from 'react-router-dom';
// 导入其他必要组件
const Product = ({ item }) => {
  const navigate = useNavigate();
  
  const handleGoToProduct = () => {
    navigate(`/product/${item._id}`);
  };

  return (
    <Container className='container product'>
      <Circle />
      <Img src={item.img} />

      <Info >
        <Icon >
          <ShoppingCartOutlinedIcon />
        </Icon>
        <Icon onClick={handleGoToProduct}>
          <SearchOutlinedIcon />
        </Icon>
        <Icon>
          <FavoriteBorderOutlinedIcon />
        </Icon>
      </Info>
    </Container>
  )
}

内容的提问来源于stack exchange,提问作者Anna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 00:15:43