Search code examples
next.jsroutesrouternext.js13

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;

The error i am getting is :
error-screenshot

expecting to see order details on /orders/[id]

The error seems to be related to the router.query object being undefined, causing a TypeError when attempting to destructure the id property from it.

I've tried checking the value of router.query and ensuring that the necessary query parameters are provided in the URL, but the error persists.

I'm not sure why router.query would be undefined in this case, especially considering that this component is part of a Next.js application where routing should be handled automatically.

Any insights or suggestions on how to troubleshoot and fix this issue would be greatly appreciated.


Solution

  • The issue with your code is you are not using the right hook.

    In newer versions of NextJS, query no longer exist on the router object, instead what you have are back, forward, prefetch, push, refresh and replace. You can console log router and see for yourself.

    The solution is to use the useParams hook from next navigation, see example below

    import { useParams } from "next/navigation";
    
    const params = useParams();
    console.log(params.id);