Reputation: 25
So, I'm trying to dynamically create the options of a select dropdown, I make the fetch of an api with the states of my country, but I don't know how to access the content inside each object..
As you can see below, the data is being pulled from the API, that is, the fetch worked, but I don't know how to create the options that will be inside the Select with each object..
import { EmailIcon, LocationIcon } from './assets/FormSvgIcons'
import { useEffect, useState } from 'react';
const SettingsForm = () => {
const [stateList, setStateList] = useState([]);
const [userLocation, setUserLocation] = useState('');
const handleLocation = () => {
setUserLocation(e.target.value);
}
useEffect(() => {
let initialStates = [];
fetch('https://servicodados.ibge.gov.br/api/v1/localidades/estados/')
.then(response => {
return response.json();
}).then(data => {
initialStates = data.map((states) => {
return states
});
console.log(initialStates);
setStateList({states: initialStates});
});
}, []);
const createDropdownOptions = () => {
const createOptions = stateList.map((state, i) => {
Object.keys(state).map(singleState => (
<option value={i}>{singleState.sigla}</option>
))
});
return createOptions;
}
return (
<form>
<div className="user-country">
<label className="white-label">
Local
</label>
<div className="input-icon-wrapper">
<div className="icon-input w-embed">
<LocationIcon />
</div>
<select
className="select-field white-select w-select"
id="locationField"
name="locationField"
onChange={handleLocation}
>
{createDropdownOptions()}
</select>
</div>
</div>
</form>
)
I know that the error is in the createDropdownOptions
function because it is responsible for creating the options, but I don't know how to do it, any light?
Upvotes: 1
Views: 259
Reputation: 11
Don't overthink. Tips:
If you have an array, you can easily map it into jsx and generate your options. You did very well, and got really close. Take a look at the changes I've done to get it working:
import { useEffect, useState } from 'react';
export const SettingsForm = () => {
const [stateList, setStateList] = useState([]);
const [userLocation, setUserLocation] = useState('');
const handleLocation = () => {
setUserLocation(e.target.value);
};
useEffect(() => {
const loadOptions = async () => {
const data = await fetch(
'https://servicodados.ibge.gov.br/api/v1/localidades/estados/'
).then((response) => {
return response.json();
});
setStateList(data);
};
loadOptions();
}, []);
return (
<form>
<div className="user-country">
<label className="white-label">Local</label>
<div className="input-icon-wrapper">
<div className="icon-input w-embed"></div>
<select
className="select-field white-select w-select"
id="locationField"
name="locationField"
onChange={handleLocation}
>
{stateList.map((state) => {
return (
<option key={state.nome} value={state.nome}>
{state.sigla}
</option>
);
})}
</select>
</div>
</div>
</form>
);
};
Hope it helps! keep up the good work and feel free to reach out in case you're still stuck!
Upvotes: 1
Reputation: 45923
First you could simplify your useEffect
to the code below. As you are making a map
where the callback returns the same object for each iteration, better you use data
as it's, because the output would be the same.
useEffect(() => {
fetch("https://servicodados.ibge.gov.br/api/v1/localidades/estados/")
.then((response) => {
return response.json();
})
.then((data) => {
console.log(data);
setStateList(data);
});
}, []);
Then change createDropdownOptions
to the code below. You can change the value
or what's displayed to nome
:
const createDropdownOptions = () => {
const createOptions = stateList.map((state) => (
<option key={state.id} value={state.sigla}>
{state.sigla}
</option>
));
return createOptions;
};
And finnaly you would need to pass the event to handleLocation
:
const handleLocation = (e) => {
setUserLocation(e.target.value);
}
Upvotes: 1
Reputation: 126
I see your problem, your logic is correct, but it is poorly implemented, once you have filtered the data, it is only rendering a new component:
import { EmailIcon, LocationIcon } from "./assets/FormSvgIcons";
import React, { useEffect, useState } from "react";
export default function SettingsForm() {
const [stateList, setStateList] = useState([]);
useEffect(() => {
fetch("https://servicodados.ibge.gov.br/api/v1/localidades/estados/")
.then((response) => {
return response.json();
})
.then((data) => {
console.log(data);
setStateList(data);
});
}, []);
return (
<form>
<div className="user-country">
<label className="white-label">Local</label>
<div className="input-icon-wrapper">
<div className="icon-input w-embed">
<LocationIcon />
</div>
<select
className="select-field white-select w-select"
id="locationField"
name="locationField"
onChange={handleLocation}
>
{stateList.map((state) => {
return <CreateDropdownOptions state={state} />;
})}
</select>
</div>
</div>
</form>
);
}
function CreateDropdownOptions({ state }) {
return (
<option key={state.id} value={state.sigla}>
{state.sigla}
</option>
);
}
I recommend using a component for each option, this will make it easier if you later need to do some action on the
Upvotes: 1