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

Next.js中router.query.id解构报错问题排查求助

问题

错误信息

Cannot destructure property 'id' of 'router.query' as it is undefined

相关代码

// data.js
export const data = {
    orders: [
        {
            id: 1,
            customer: "Customer A",
            items: [
                { id: 1, name: "Item 1", quantity: 5 },
                { id: 2, name: "Item 2", quantity: 3 }
            ],
            status: "Pending"
        },
        {
            id: 2,
            customer: "Customer B",
            items: [
                { id: 1, name: "Item 1", quantity: 2 },
                { id: 3, name: "Item 3", quantity: 1 }
            ],
            status: "Completed"
        }
    ],
    items: [
        { id: 1, name: "Item 1", stock: 20 },
        { id: 2, name: "Item 2", stock: 15 },
        { id: 3, name: "Item 3", stock: 10 }
    ]
};
// [id]/page.js
"use client";

import { useRouter } from "next/navigation";
import { data } from "../../../utils/data";

const OrderDetails = () => {
    const router = useRouter();
    const { id } = router.query;

    if (!id) {
        return <div>No order ID provided</div>;
    }

    const order = data.orders.find(order => order.id === parseInt(id));

    if (!order) {
        return <div>Order not found</div>;
    }

    return (
        <div className="container mx-auto p-4">
            <h1 className="text-2xl font-bold mb-4">Order Details - {order.id}</h1>

            <p>Customer: {order.customer}</p>
            <p>Status: {order.status}</p>
            <h2 className="text-xl font-semibold ">Items: </h2>
            <ul>
                {
                    order.items.map(item => (
                        <li key={item.id} className="border-b py-2">
                            <p>Name: {item.name}</p>
                            <p>Quantity: {item.quantity}</p>
                            <p>Stock: {data.items.find(i => i.id === item.id).stock}</p>
                        </li>
                    ))
                }
            </ul>
            <button className="mt-4 bg-green-500 text-white px-4 py-2 rounded">Mark as Completed</button>
        </div>
    );
};

export default OrderDetails;
// orders/page.js
"use client";

import { useEffect, useState } from "react";
import { data } from "../../utils/data";
import Link from 'next/link';

const OrderList = () => {
    const [orders, setOrders] = useState(data.orders);
    const [filter, setFilter] = useState('');

    useEffect(() => {
        if (filter) {
            setOrders(data.orders.filter(order => order.status === filter));
        } else {
            setOrders(data.orders);
        }
    }, [filter]);

    return (
        <div className="container mx-auto p-4">
            <h1 className="text-2xl font-bold mb-4">Orders List</h1>
            <div className="mb-4">
                <label htmlFor="statusFilter" className="mr-2">Filter by status:</label>
                <select
                    id="statusFilter"
                    onChange={e => setFilter(e.target.value)}
                    className="border rounded px-2 py-1 bg-black"
                >
                    <option value="">All</option>
                    <option value="Pending">Pending</option>
                    <option value="Completed">Completed</option>
                </select>
            </div>
            <ul>
                {orders.map(order => (
                    <li key={order.id} className="border-b py-2">
                        <div className="flex justify-between">
                            <div>
                                <h2 className="text-xl font-semibold">Order ID: {order.id}</h2>
                                <p>Customer: {order.customer}</p>
                                <p>Status: {order.status}</p>
                                <p>Item Count: {order.items.length}</p>
                            </div>
                            <Link href={`/orders/` + orders.id}>
                                <button className="text-blue-500">View Details</button>
                            </Link>
                        </div>
                    </li>
                ))}
            </ul>
        </div>
    );
};

export default OrderList;
// inventory/page.js
"use client";

import { useState } from "react";
import { data } from "../../utils/data";

const InventoryList = () => {
    const [items, setItems] = useState(data.items);

    const handleDelete = (id) => {
        setItems(items.filter(item => item.id !== id));
    };

    return (
        <div className="container mx-auto p-4">
            <h1 className="text-2xl font-bold mb-4">Inventory List</h1>
            <ul>
                {items.map(item => (
                    <li key={item.id} className="border-b py-2 flex justify-between">
                        <div>
                            <p>Name: {item.name}</p>
                            <p>Stock: {item.stock}</p>
                        </div>
                        <button
                            onClick={() => handleDelete(item.id)}
                            className="text-red-500"
                        >
                            Delete
                        </button>
                    </li>
                ))}
            </ul>
        </div>
    );
};

export default InventoryList;

问题描述

我希望访问/orders/[id]页面时能正常展示订单详情,但现在触发了上面的错误。错误原因是router.query未定义,解构id时抛出TypeError。我已经检查过router.query的值,也确认URL里传了必要的查询参数,但问题还是没解决。不知道在Next.js里router.query为什么会未定义,求排查和修复的建议。


解答

核心问题分析

  1. App Router路由参数获取方式错误:你用的是Next.js 13+的App Router(app/目录结构),但next/navigation的useRouter不再提供query属性,动态路由参数得用useParams钩子获取。
  2. 订单列表页链接错误:orders/page.js里的Link写了orders.id,但orders是数组,没有id属性,导致生成的链接是/orders/undefined,进一步引发参数问题。

修复步骤

1. 修改订单详情页([id]/page.js)

替换useRouter为useParams来获取动态路由参数:

"use client";

// 导入useParams替代useRouter
import { useParams } from "next/navigation";
import { data } from "../../../utils/data";

const OrderDetails = () => {
    const params = useParams();
    const id = params.id;

    if (!id) {
        return <div>No order ID provided</div>;
    }

    const order = data.orders.find(order => order.id === parseInt(id));

    if (!order) {
        return <div>Order not found</div>;
    }

    return (
        <div className="container mx-auto p-4">
            <h1 className="text-2xl font-bold mb-4">Order Details - {order.id}</h1>

            <p>Customer: {order.customer}</p>
            <p>Status: {order.status}</p>
            <h2 className="text-xl font-semibold ">Items: </h2>
            <ul>
                {
                    order.items.map(item => (
                        <li key={item.id} className="border-b py-2">
                            <p>Name: {item.name}</p>
                            <p>Quantity: {item.quantity}</p>
                            <p>Stock: {data.items.find(i => i.id === item.id).stock}</p>
                        </li>
                    ))
                }
            </ul>
            <button className="mt-4 bg-green-500 text-white px-4 py-2 rounded">Mark as Completed</button>
        </div>
    );
};

export default OrderDetails;

2. 修复订单列表页的链接(orders/page.js)

把orders.id改成当前遍历项的order.id:

<Link href={`/orders/${order.id}`}>
    <button className="text-blue-500">View Details</button>
</Link>

3. 可选优化:处理加载状态

如果需要更严谨的体验,可以在参数未加载时显示加载提示:

if (!id) {
    return <div>Loading...</div>;
}

关键区别说明

Next.js 13+的App Router和旧Pages Router的API逻辑不同:

  • Pages Router里useRouter()返回的对象包含query属性,用来获取路由参数和查询参数
  • App Router里,动态路由参数用useParams()获取,URL查询参数用useSearchParams(),next/navigation的useRouter不再提供query字段

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 20:53:10