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

React Router双参数页面直接访问时Redux数据无法获取问题

React Router 单页应用路由参数相关数据加载异常问题

问题现象

  • 应用页面数量由JSON商品数据决定:主页通过props传递商品类型,其他页面使用:section和:page_number双路由参数
  • 导航栏点击进入双参数页面时功能正常;但直接在地址栏输入路径或刷新页面时,GoodsList组件无法加载商品列表——组件和路由参数均正常,但Redux的fetchProducts数据获取逻辑未执行
  • 先访问主页再跳转双参数页面时恢复正常;移除:page_number参数后问题消失

相关代码

Sections组件

import { Routes, Route } from 'react-router-dom';
import GoodsList from './GoodsList';
import Pages from './Pages';

function Sections() {
    return (
        <Routes>
            <Route path='' element={<><div className="pageContent" data-main="true"><p>Novelties</p><GoodsList goods="novelties" /><p>Hot</p><GoodsList goods="hot" /></div></>} />
            <Route path='/:section/:page_number' element={<><div className='pageContent'><GoodsList /><Pages /></div></>} />
        </Routes>
    )
}
import { Link } from 'react-router-dom';

function Menu() {
    return (
        <nav className='menu'>
            <ul>
                <li><Link to="">Main</Link></li>
                <li><Link to="figures/1">Figures</Link></li>
                <li><Link to="dakimakuras/1">Dakimakuras</Link></li>
                <li><Link to="manga/1">Manga</Link></li>
                <li><Link to="other/1">Other merch</Link></li>
            </ul>
        </nav>
    )
}

GoodsList组件

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchProducts } from '../redux/fetchDataReducer';
import { useParams } from 'react-router-dom';

function GoodsList(props) {
    const params = useParams();
    const goods = returnGoods();
    function returnGoods() {
        if (document.location.pathname == "/") {
            return props.goods
        }
        return params.section
    }
    
    const dispatch = useDispatch();
    useEffect(() => {
        dispatch(fetchProducts());
    }, [])
    
    const products = useSelector(state => state.fetchDataReducer.products);
    
    return (
        <div className="list">
            {products && products[goods].map((good, i) => (
                <div className="productCard" key={i}>
                    <div className="productPicture">
                        <img src={good.pic} alt="ERROR" />
                    </div>
                    <p className="productName">{good.name}</p>
                </div>
            ))}
        </div>
    )
}

Pages组件

import { useSelector } from "react-redux";
import { Link, useParams } from 'react-router-dom';

function Pages() {
    const params = useParams();
    const products = useSelector(state => state.fetchDataReducer.products);
    const currentProduct = products ? products[params.section] : [];
    const pageLinks = [];

    let numberOfPages = () => {
        if ((currentProduct.length / 8) % 1 == 0) {
            return currentProduct.length / 8
        }
        else return Math.floor((currentProduct.length / 8) + 1)
    }

    for (let x = 1; x < (numberOfPages() + 1); x++) {
        pageLinks.push(<Link to={`/${params.section}/${x}`} className="pageLink" key={x}>{x}</Link>);
    }
    
    return (
        <div className="pageList">
            {pageLinks}
        </div>
    )
}

问题根源

  1. useEffect依赖缺失:GoodsList的useEffect仅在组件挂载时执行一次(空依赖数组),直接刷新/地址栏进入时,组件挂载后Redux无商品数据,但后续无重新触发获取的逻辑;而从主页跳转时,主页已触发过fetchProducts,Redux已有数据,因此能正常渲染。
  2. 路由参数未作为响应式依赖:路由参数变化(包括首次加载双参数路由)时,useEffect未触发数据获取,导致数据未加载。
  3. 路径判断不可靠:使用document.location.pathname判断页面,不如React Router提供的useLocation组件式API可靠,且可能在路由参数未完全解析时就执行判断,导致params.section获取不准确。

修复方案

1. 完善GoodsList组件的响应式逻辑

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchProducts } from '../redux/fetchDataReducer';
import { useParams, useLocation } from 'react-router-dom';

function GoodsList(props) {
    const params = useParams();
    const location = useLocation();
    const dispatch = useDispatch();

    // 用useLocation替代document.location,更符合React组件逻辑
    const goods = location.pathname === "/" ? props.goods : params.section;

    useEffect(() => {
        // 检查Redux中是否已有数据,无数据则触发获取
        const existingProducts = useSelector(state => state.fetchDataReducer.products);
        if (!existingProducts) {
            dispatch(fetchProducts());
        }
    }, [dispatch, location.pathname, params.section]); // 添加路由相关依赖,确保路由变化时重新执行

    const products = useSelector(state => state.fetchDataReducer.products);
    
    return (
        <div className="list">
            {/* 用可选链避免数据未加载时的报错 */}
            {products && products[goods]?.map((good, i) => (
                <div className="productCard" key={i}>
                    <div className="productPicture">
                        <img src={good.pic} alt={good.name} />
                    </div>
                    <p className="productName">{good.name}</p>
                </div>
            ))}
        </div>
    )
}

2. 全局初始化商品数据(可选优化)

在应用入口或根组件中触发数据获取,确保任何路由下都能拿到数据:

// App.js
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { fetchProducts } from './redux/fetchDataReducer';
import Menu from './Menu';
import Sections from './Sections';

function App() {
    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(fetchProducts());
    }, [dispatch]);

    return (
        <div className="app">
            <Menu />
            <Sections />
        </div>
    );
}

3. 优化Pages组件的容错处理

避免数据未加载时出现计算错误:

import { useSelector } from "react-redux";
import { Link, useParams } from 'react-router-dom';

function Pages() {
    const params = useParams();
    const products = useSelector(state => state.fetchDataReducer.products);

    // 数据未加载时显示加载状态
    if (!products || !products[params.section]) {
        return <div className="pageList">加载中...</div>;
    }

    const currentProduct = products[params.section];
    const pageLinks = [];

    // 简化分页计算逻辑
    const numberOfPages = Math.ceil(currentProduct.length / 8);

    for (let x = 1; x <= numberOfPages; x++) {
        pageLinks.push(<Link to={`/${params.section}/${x}`} className="pageLink" key={x}>{x}</Link>);
    }
    
    return (
        <div className="pageList">
            {pageLinks}
        </div>
    )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 07:00:25