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

React重渲染更新值报ordersToDisplay初始化前访问引用错误

问题根源

你遇到的初始化报错核心是两个问题:

  • 变量命名冲突:顶部导入的JSON订单数据、组件内useMemo声明的筛选后订单变量用了完全相同的名字ordersToDisplay,JS执行到useMemo回调时,会优先读取当前函数作用域内的ordersToDisplay变量,但此时该变量还未完成初始化,触发暂时性死区报错。
  • 逻辑错位:你在按钮点击回调里直接取数组长度,此时筛选逻辑还未执行,拿到的永远是全量订单的长度,无法同步筛选后的数量;另外路由配置错误把动态状态拼入静态路由定义,会导致路由匹配异常。
修复方案

按以下步骤调整代码即可:

  • 首先重命名导入的原始JSON数据,从根源解决命名冲突
  • 修正useMemo内的筛选逻辑,基于原始数据做过滤
  • 新增副作用监听,在筛选后的订单列表变化时,同步更新文档标题和全局状态
  • 调整路由配置,路由路径保持静态规则,动态订单数仅用于标题更新(如果确实需要路径带订单数,用动态路由参数写法即可,不要直接把state拼入path定义)

修复后的OrdersPage组件代码

import { Col, Row } from "antd";
import { useContext, useEffect, useMemo, useState } from "react";
import Order from "../components/Order";
import { AppContext } from "../context/Context";
import AntButton from "../elements/Button";
// 重命名原始导入的订单数据,避免和筛选后变量重名
import rawOrders from "../orders.json";

const OrdersPage = () => {
    const [filteringStatus, setFilteringStatus] = useState("");
    const { setOrderAmount } = useContext(AppContext)

    const setDiplayAcceptedOrders = () => {
        setFilteringStatus("accepted");
    };
    
    const setDiplayCompletedOrders = () => {
        setFilteringStatus("complete");
    };
    
    const setDiplayInProgressOrders = () => {
        setFilteringStatus("inProgress");
    };

    // 基于原始数据做筛选,返回最终展示的订单列表
    const ordersToDisplay = useMemo(() => {
        if (filteringStatus) {
          return rawOrders.filter((i) => i.orderStatus === filteringStatus);
        }
        return rawOrders;
    }, [filteringStatus]);

    // 监听展示订单列表变化,同步更新文档标题和全局状态
    useEffect(() => {
        const orderNumber = ordersToDisplay.length;
        // 更新文档标题
        document.title = `/${orderNumber}orders`;
        // 更新全局orderAmount状态
        setOrderAmount(orderNumber);
    }, [ordersToDisplay, setOrderAmount])

    return(
        <div className="container">
            <Row justify="space-between" align="middle">
                <Col span={6}>
                    <h1>Orders</h1>
                </Col>
                <Col span={6}>
                    <AntButton onClick={setDiplayAcceptedOrders} name="Accepted"/>
                </Col>
                <Col span={6}>
                    <AntButton onClick={setDiplayInProgressOrders}  name="In Progress"/>
                </Col>
                <Col span={6}>
                    <AntButton onClick={setDiplayCompletedOrders} name="Complete"/>
                </Col>
            </Row>
            <Row>
                <Col span={12}>
                    <h3>{filteringStatus == "" ? "All Orders" : filteringStatus}</h3>
                    {ordersToDisplay.map((e) => {
                        return(
                            <Order
                            key={e.id}
                            productName={e.productName}
                            dateOrdered={e.dateOrdered}
                            orderStatus={e.orderStatus}
                        />
                        )
                    })}
                </Col>
            </Row>
        </div>
    )
}

export default OrdersPage;

App组件调整说明

你之前把动态state直接拼入路由path的写法是错误的,useRoutes的路由定义只需要写静态匹配规则即可,如果你不需要路径随订单数变化,直接把订单页路径改成固定的/orders即可:

const App = () => {
    const [orderAmount, setOrderAmount] = useState("")

    const Routes = useRoutes([
        {path: "/", element: <HomePage/>},
        // 路由路径保持静态,动态值仅用于标题更新
        {path: "/orders", element: <OrdersPage/>}
    ])
    
  return (
        <AppContext.Provider value={{
            orderAmount, setOrderAmount
        }}>
            <div>
                {Routes}
            </div>
        </AppContext.Provider>
  );
};

export default App;

如果你确实需要路由地址也同步显示订单数量(比如地址栏显示/3orders),不要用上面的静态路由写法,应该用路由导航的方式在orderAmount变化时主动跳转,不要直接修改路由定义的path值。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:27:24