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

React Router DOM跳转商品详情页URL异常问题求助

商品详情页路由跳转URL转义异常问题

路由规则与目标URL格式配置正确,但跳转至商品详情页时URL出现异常转义。预期URL为localhost:3000/product/661542f7c301d72e2fb103c4,实际跳转后得到http://localhost:3000/%7B%60/product/$%7Bproduct._id%7D%60%7D。

相关代码

App.js

import './App.css';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Footer from './components/layout/Footer';
import Header from './components/layout/Header';
import Home from './components/Home';
import ProductDetails from './components/product/ProductDetails';

function App() {
  return (
    <Router>
      <div className="App">
        <Header />
        <div className="container container-fluid">
          <Routes>
            <Route path="/" Component={Home} exact />
            <Route path="/product/:id" component={ProductDetails} exact />
          </Routes>
        </div>
        <Footer />
      </div>
    </Router>
  );
}

export default App;

ProductDetails组件(模板)

import React, { Fragment, useEffect } from "react";
import { useAlert } from "react-alert";
import { Carousel } from 'react-bootstrap'
import { useDispatch, useSelector } from "react-redux";
import { getProductDetails, clearErrors } from "../../actions/productActions";
import Loader from "../layout/Loader";
import MetaData from "../layout/MetaData";

const ProductDetails = () => {
  return (
    <div className="row f-flex justify-content-around">
      <div className="col-12 col-lg-5 img-fluid" id="product_image">
        <img
          src="https://i5.walmartimages.com/asr/
                1223a935-2a61-480a-95a1-21904ff8986c_1.17fa3d7870e3d9b1248da7b1144787f5.jpeg?
                odnWidth=undefined&odnHeight=undefined&odnBg=ffffff"
          alt="sdf"
          height="500"
          width="500"
        />
      </div>

      <div className="col-12 col-lg-5 mt-5">
        <h3>onn. 32” className HD (720P) LED Roku Smart TV (100012589)</h3>
        <p id="product_id">Product # sklfjdk35fsdf5090</p>

        <hr />

        <div className="rating-outer">
          <div className="rating-inner"></div>
        </div>
        <span id="no_of_reviews">(5 Reviews)</span>

        <hr />

        <p id="product_price">$108.00</p>
        <div className="stockCounter d-inline">
          <span className="btn btn-danger minus">-</span>

          <input
            type="number"
            className="form-control count d-inline"
            value="1"
            readOnly
          />

          <span className="btn btn-primary plus">+</span>
        </div>
        <button
          type="button"
          id="cart_btn"
          className="btn btn-primary d-inline ml-4"
        >
          Add to Cart
        </button>

        <hr />

        <p>
          Status: <span id="stock_status">In Stock</span>
        </p>

        <hr />

        <h4 className="mt-2">Description:</h4>
        <p>
          Binge on movies and TV episodes, news, sports, music and more! We
          insisted on 720p High Definition for this 32" LED TV, bringing out
          more lifelike color, texture and detail. We also partnered with Roku
          to bring you the best possible content with thousands of channels to
          choose from, conveniently presented through your own custom home
          screen.
        </p>
        <hr />
        <p id="product_seller mb-3">
          Sold by: <strong>Amazon</strong>
        </p>

        <button
          id="review_btn"
          type="button"
          className="btn btn-primary mt-4"
          data-toggle="modal"
          data-target="#ratingModal"
        >
          Submit Your Review
        </button>

        <div className="row mt-2 mb-5">
          <div className="rating w-50">
            <div
              className="modal fade"
              id="ratingModal"
              tabIndex="-1"
              role="dialog"
              aria-labelledby="ratingModalLabel"
              aria-hidden="true"
            >
              <div className="modal-dialog" role="document">
                <div className="modal-content">
                  <div className="modal-header">
                    <h5 className="modal-title" id="ratingModalLabel">
                      Submit Review
                    </h5>
                    <button
                      type="button"
                      className="close"
                      data-dismiss="modal"
                      aria-label="Close"
                    >
                      <span aria-hidden="true">&times;</span>
                    </button>
                  </div>
                  <div className="modal-body">
                    <ul className="stars">
                      <li className="star">
                        <i className="fa fa-star"></i>
                      </li>
                      <li className="star">
                        <i className="fa fa-star"></i>
                      </li>
                      <li className="star">
                        <i className="fa fa-star"></i>
                      </li>
                      <li className="star">
                        <i className="fa fa-star"></i>
                      </li>
                      <li className="star">
                        <i className="fa fa-star"></i>
                      </li>
                    </ul>

                    <textarea
                      name="review"
                      id="review"
                      className="form-control mt-3"
                    ></textarea>

                    <button
                      className="btn my-3 float-right review-btn px-4 text-white"
                      data-dismiss="modal"
                      aria-label="Close"
                    >
                      Submit
                    </button>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default ProductDetails;

后端API响应(Postman测试)

请求地址:{{DOMAIN}}/api/v1/product/661542f7c301d72e2fb103c4

{
    "success": true,
    "product": {
        "_id": "661542f7c301d72e2fb103c4",
        "name": "Diamonds - Hip Hop Samples",
        "price": 10,
        "ratings": 4,
        "images": [
            {
                "public_id": "product/productNumber211",
                "url": "//cymatics.fm/cdn/shop/products/diamonds-h1200-min_1080x.png?v=1579721670 1080w",
                "_id": "661542f7c301d72e2fb103c5"
            }
        ],
        "category": "Pack",
        "seller": "Alexandar",
        "numOfReviews": 10,
        "reviews": [],
        "user": "65f9975e64c530b7ccde88f3",
        "createdAt": "2024-04-09T13:30:31.787Z",
        "__v": 0
    }
}

Redux Action(获取商品详情)

export const getProductDetails = (id) => async (dispatch) => {
    try {
        dispatch({ type: PRODUCTS_DETAILS_REQUEST });

        const {data} = await axios.get(`/api/v1/product/${id}`);

        dispatch({
            type: PRODUCTS_DETAILS_SUCCESS,
            payload: data.product
        });
    } catch (error) {
        dispatch({
            type: PRODUCTS_DETAILS_FAIL,
            payload: error.response.data.message
        });
    }
};

问题分析与解决方案

问题原因

URL转义异常是因为跳转时模板字符串语法(如${product._id})被当成普通字符串处理,进而被URL编码。这种情况通常出现在商品列表的跳转代码中,比如错误地用引号包裹模板字符串,或未使用JSX表达式语法解析动态路径。

正确跳转写法

假设跳转逻辑在商品列表组件中,使用React Router的Link组件时,需用模板字符串动态生成路径:

import { Link } from 'react-router-dom';

// 商品列表项内的跳转代码
<Link to={`/product/${product._id}`}>查看详情</Link>

若使用普通<a>标签,写法类似:

<a href={`/product/${product._id}`}>查看详情</a>

额外检查点

  1. 确认product._id存在且值正确:跳转前可打印product对象,确保_id字段不为空或undefined。
  2. 统一React Router v6路由属性:App.js中Home路由用Component(大写C),ProductDetails用component(小写c),v6版本统一使用element属性,建议修正为:
<Route path="/" element={<Home />} exact />
<Route path="/product/:id" element={<ProductDetails />} exact />

该修正虽非URL转义直接原因,但符合v6规范,可避免潜在问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 06:34:57