I am very new to React + Typescript and having issues with setState.
Workflow:
- Making a call to the API and pulling all of the locations. (working)
- Then building out the locations data to be compatible with Mantine MultiSelect component. (working)
- I am loading those locations to a multiselect. (working)
- If user selects locations I make a call to the API and return reservations for all selected locations(working)
- setState so the reservationsData contains data from all API calls (not working)
Questions and issues:
- useEffect is triggering twice, googling this issue it is because I am development mode? That is why I implemented a check to see if that location already exists because it was adding it twice and Mantine MultiSelect does not like duplicate values.
- When trying to setReservationData, I am unable to add onto previous data. When I display the reservationData it is only showing for the first option that was clicked.
setReservationData(prevReservationData => ({
...prevReservationData,
data
}))
- Any other advice on how to refactor this and how I should break this into further components.
Thanks
import React from 'react';
import { MultiSelect } from '@mantine/core';
export const Filters = () => {
const [regionData, setRegionData] = React.useState([] as any[])
const [reservationData, setReservationData] = React.useState([])
const [selectedLocations, setSelectedLocations] = React.useState<string[]>([]);
interface Locations {
group: string;
items: {value: string, label: string}[];
}
const locations: Locations[] = [];
React.useEffect(() => {
async function getCityData(locations: any) {
const res = await fetch("https://url.com/locations/list?token=123")
const data = await res.json()
for(let i = 0; i < data.length; i++){
var temp = [];
if(data[i]['Cities']){
for(let j = 0; j < data[i]['Cities'].length; j++){
temp.push({value: data[i]['Cities'][j]['Id'], label: data[i]['Cities'][j]['Name']})
}
var found = false;
for(let k = 0; k < locations.length; k++){
if(data[i]['Name'] === locations[k]['group']){
found = true;
}
}
if(!found){
locations.push({ group: data[i]['Name'], items: temp})
}
}
}
setRegionData(locations)
}
getCityData(locations)
}, [])
const handleLocationChange = (value: string[]) => {
setSelectedLocations(value);
}
React.useEffect(() => {
async function getData(location: string) {
const res = await fetch(`https://url.com/locations/data?token=123=${location}`)
const data = await res.json()
setReservationData(prevReservationData => ({
...prevReservationData,
data
}))
}
if(selectedLocations.length > 0){
for(let i = 0; i < selectedLocations.length; i++){
getData(selectedLocations[i]);
}
}else{
setReservationData([]);
}
}, [selectedLocations])
return (
<div>
<MultiSelect
label="Locations"
placeholder="Pick your location(s)"
value={selectedLocations}
data={regionData}
onChange={handleLocationChange}
/>
{ JSON.stringify(reservationData) }
</div>
);
}
Data from API
Locations
[
{
"Id": "111",
"Name": "West",
"Cities": [
{
"Id": "111a",
"Name": "Vancouver"
},
{
"Id": "111b",
"Name": "Seattle"
}
]
},
{
"Id": "222",
"Name": "East",
"Cities": [
{
"Id": "222a",
"Name": "Toronto"
},
{
"Id": "222b",
"Name": "Montreal"
}
]
}
]
Reservations
[
{
"Id": "111a1",
"Name": "Building A",
"StreetAddress": "123 Random St"
},
{
"Id": "111a2",
"Name": "Building B",
"StreetAddress": "22 Example Dr"
}
]
Edit: Thanks to Ben it is working now. I have changed reservationData to type any[]
const [reservationData, setReservationData] = React.useState([] as any[])
and changed:
React.useEffect(() => {
async function getData(location: string) {
const res = await fetch(`https://url.com/locations/data?token=123=${location}`)
const data = await res.json()
console.log(data)
setReservationData(prevReservationData => [
...prevReservationData,
data
])
}
setReservationData([]);
if(selectedLocations.length > 0){
setReservationData([]);
for(let i = 0; i < selectedLocations.length; i++){
getData(selectedLocations[i]);
}
}
}, [selectedLocations])
It appears to be working now. I setState to blank then add onto it again to avoid duplicates.
If there is a way to improve me code please let me know.
Reservations data is an array of Reservation objects. So, your state update should look something like this: