I'm just starting out learning React/NextJS and need to put together a basic frontend for an API we have. To start with, I'm trying to display a list of clients then get a list of products for the selected client, using client side components and state to manage the selected items.
So far, my app looks like:
/app/page.tsx
import { Clients } from "@/components/clients";
export default async function Home() {
return (
<div>
<Clients />
</div>
);
}
/components/clients.tsx
'use client';
import { useState } from 'react';
import { ClientList } from './clientList';
import { ProductList } from './productList';
export const Clients = () => {
const [selectedClient, setSelectedClient] = useState(null);
return (
<div className="h-full flex justify-start items-start md:overflow-hidden">
<div className="md:w-60">
<ClientList onSelect={setSelectedClient}/>
</div>
<div className="flex-grow">
<ProductList client={selectedClient} />
</div>
</div>
);
}
/components/clientList.tsx
'use client';
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { Client } from "@/app/lib/definitions";
import { getClients } from "../app/lib/data";
export const ClientList = ({ onSelect }) => {
const [items, setItems] = useState([]);
useEffect(() => {
getClients().then((data) => setItems(data));
}, []);
return (
<div>
<div>Clients</div>
<ul>
{items.map((item: Client) => (
<li key={item.Uid} onClick={() => onSelect(item)}>{item.Name}</li>
))}
</ul>
</div>
);
};
/components/productList.tsx
'use client';
import { useEffect, useState } from 'react';
import { getProducts } from "@/app/lib/data";
import { Client } from '@/app/lib/definitions';
export const ProductList = ({ client } : { client:Client}) => {
const [items, setItems] = useState([]);
if (!client) {
return <div>Products</div>
}
useEffect(() => {
getProducts(client.Uid).then((data) => setItems(data));
}, []);
return (
<div>
<div>Products</div>
<ul>
{items.map((item) =>
<li key={item.Uid}>{item.Name}</li>
)}
</ul>
</div>
);
};
The data is loading from async functions using fetch. The app is loading clients ok, but if I select a client, I get the following:
React has detected a change in the order of Hooks called by ProductList. This will lead to bugs and errors if not fixed.
If I remove the null check on client in the productList component, it gets very upset about trying to access properties that don't exist on a null object.
Given I am very new to all this, I'm sure I've got some pattern or something equally simple wrong here.
In productList, try to pass dependency for client in useEffect,
useEffect(() => {
if(client)
{
getClients().then((data) => setItems(data));
}
}, [client]);
also ensure that items contains some data
<ul>
{items && items.map((item) =>
<li key={item.Uid}>
{item.Name}
</li>
)}
</ul>