I'm making a small flight tracker system and I'm encountering an issue. Here's the code for a "choose your flight" page:
"use client"
interface MyPageProps {
searchParams: Promise<FlightSearchPanelData>;
}
export default function SelectFlight( {searchParams} : MyPageProps ) {
const params = React.use(searchParams);
const router = useRouter();
const [flightData, setFlightData] = useState<ResultingFlightDetail[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [selectedFlightData, setSelectedFlightData] = useState<ResultingFlightDetail>();
const isUsingFlightNumber = params.isUsingFlightNumber || "false";
const flightFrom = params.flightFrom || "";
const flightTo = params.flightTo || "";
const flightNumber = params.flightNumber || "";
const flightDate = params.flightDate || "";
useEffect(() => {
const fetchFlightData = async () => {
try {
setLoading(true);
const params = await searchParams;
const url = new URL(`${BASE_API_URL}/api/flightsByFromTo`);
url.searchParams.append('flightNumber', flightNumber);
url.searchParams.append('flightFrom', flightFrom);
url.searchParams.append('flightTo', flightTo);
url.searchParams.append('flightDate', flightDate);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setFlightData(result);
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred');
console.log("error", err);
} finally {
setLoading(false);
}
};
fetchFlightData();
}, []);
const handleClick = (event: React.MouseEvent) => {
if (flightData.length > 0 && !loading) {
const clickedId = parseInt(event.currentTarget.id);
setSelectedFlightData(flightData[clickedId]);
sessionStorage.setItem('individualFlightData', JSON.stringify(selectedFlightData));
//router.push(`/flight/passenger_info`);
}
}
if (error) {
return (
<div className="grid min-h-50 grid-cols-20 flex">
<div className="col-start-2 col-span-18 flex flex-col mt-15 -mx-8 z-2">
<div className="flex justify-center">
Error: {error}
</div>
</div>
<div className="fixed bottom-0 left-0 w-full">
<FooterPanelWithBg />
</div>
</div>
);
}
return (
<div className="grid min-h-screen grid-cols-20 flex">
<div className="flex flex-col col-start-2 col-span-18 mt-15">
<div className="mx-60">
{loading ?
<div className="flex justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-gray-900" />
</div>
:
<div className="space-y-10">
{flightData.map((data: ResultingFlightDetail, idx: number) => {
return (
<div
id={idx.toString()}
key={idx}
className={
selectedFlightData?.id === (idx + 1).toString() ?
"w-full h-26 p-4 rounded-md shadow-md flight-details-card-selected" :
"w-full h-26 p-4 rounded-md shadow-md flight-details-card"
}
onClick={handleClick}>
<div className="col-start-2 flex justify-end">
<div>
<div className="flight-details-flight-num flex justify-end">
{data.airlineCode || "XX"} {data.flightNum || "000"}
</div>
<div className="flight-details-flight-time">
{formatTimeToLongString(data.departureDateTime)} - {formatTimeToLongString(data.arrivalDateTime)}
</div>
</div>
</div>
</div>
)
})}
</div>
}
</div>
</div>
</div>
);
}
While this seemingly fetches and displays the data, I have an issue with the OnClick function of the resulting divs.
The first issue is that by the first click, the array flightData is empty (and logging it confirms that), so selectedFlightData ends up being undefined. This seems strange to me as it's not supposed to show the data until it's loaded. I have to click again to actually see the flightData populated and to properly set a selectedFlightData.
The second issue is that clicking on a div retains the last ID. So, for example, I click on the first item, it returns an undefined, I click on it again, it grabs the index of the first object. If I change my mind and select, say, the second item, the selectedFlightData doesn't change - it's still the first item. I have to click the second item again to get it to be selected.
As suggested, this
selectedFlightData?.id === (idx + 1).toString()
is wrong (index mismatch), should be
selectedFlightData?.id === idx.toString()
Also, below code is wrong, as state does not update immediately, so you need to use value that you used to set the state to:
sessionStorage.setItem('individualFlightData', JSON.stringify(selectedFlightData))
should be changed to
sessionStorage.setItem('individualFlightData', JSON.stringify(flightData[clickedId]))