Stack: Next.JS, Postgres SQL (hosted from vercel), tailwindcss, shadcn
I am having issues populating data for the Shadcn combobox component. The page renders and it defaults to “Select Case”:
Here are some console logs after page load (without clicking anything):
Cases state updated: []
Value state updated: null
Cases state updated: []
Value state updated: null
[Fast Refresh] rebuilding
Fetched cases: (2) [{…}, {…}]
Cases state updated: (2) [{…}, {…}]
[Fast Refresh] rebuilding
Fetched cases: (2) [{…}, {…}]
Cases state updated: (2) [{…}, {…}]
The data is fetched properly but then when I click the component to get a dropdown with the values listed… I get this
RuntimeError:TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
at Function.from (<anonymous>)
at A (index.mjs:1:3990)
at U (index.mjs:1:3003)
at index.mjs:1:1763
at index.mjs:1:10381
at Map.forEach (<anonymous>)
at index.mjs:1:10370
at commitHookEffectListMount (react-dom.development.js:21102:23)
at commitHookLayoutEffects (react-dom.development.js:21212:7)
at commitLayoutEffectOnFiber (react-dom.development.js:21410:11)
at recursivelyTraverseLayoutEffects
'use client';
import * as React from 'react';
import { Check, ChevronsUpDown } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
} from '@/components/ui/command';
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/components/ui/popover';
interface Case {
id: number;
name: string;
}
export function ClientCombobox() {
const [open, setOpen] = React.useState(false);
const [value, setValue] = React.useState<string | null>(null);
const [cases, setCases] = React.useState<Case[]>([]);
React.useEffect(() => {
async function fetchCases() {
try {
const response = await fetch('/api/cases');
if (response.ok) {
const data = await response.json();
console.log('Fetched cases:', data);
setCases(Array.isArray(data) ? data : []); // Ensure data is an array
} else {
console.error('Failed to fetch cases');
}
} catch (error) {
console.error('Error fetching cases:', error);
}
}
fetchCases();
}, []);
React.useEffect(() => {
console.log('Cases state updated:', cases);
// If the value is no longer in the cases array, reset it
if (value && !cases.some(caseItem => caseItem.id.toString() === value)) {
setValue(null);
}
}, [cases]);
React.useEffect(() => {
console.log('Value state updated:', value);
}, [value]);
const handleSelect = (currentValue: string) => {
console.log('Selected value:', currentValue);
setValue(currentValue === value ? null : currentValue);
setOpen(false);
};
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="w-[200px] justify-between"
>
{value ? cases.find((caseItem) => caseItem.id.toString() === value)?.name : 'Select case...'}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<Command>
<CommandInput placeholder="Search case..." />
<CommandEmpty>No case found.</CommandEmpty>
<CommandGroup>
{cases.length > 0 ? (
cases.map((caseItem) => (
<CommandItem
key={caseItem.id}
value={caseItem.id.toString()}
onSelect={handleSelect}
>
<Check
className={cn(
'mr-2 h-4 w-4',
value === caseItem.id.toString() ? 'opacity-100' : 'opacity-0'
)}
/>
{caseItem.name}
</CommandItem>
))
) : (
<CommandEmpty>No case found.</CommandEmpty>
)}
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
);
}
I would like the combobox dropdown to display the names from the fetched data.