create dynamic select with Reactjs + Hooks

Asked

Viewed 1,463 times

-2

Hello. I am trying to create a form with four selects (Animal, Size, State and City) the state and city selects that are being a problem. One makes a request to present the Brazilian states (is working normally) and the other select will display the cities of the selected state, but I can not continue this part, I could not pass the id dynamically in the URL of the municipalities. Instead of passing only a selected id is going to the entire array.

Follow the code below as far as I can:

const FormFinderPets = () => {

  const [species, setSpecies] = useState('');
  const [port, setPort] = useState('');
  const [UFs, setUFs] = useState('');
  const [cities, setCities] = useState('');
  const [listUFs, setListUFs] = useState([]);
  const [listCities, setListCities] = useState([]);

  useEffect(() => {

    const populatedStates = axios.get('https://servicodados.ibge.gov.br/api/v1/localidades/estados');
    populatedStates.then((res) => {
      setListUFs(res.data);

     const stateId = res.data.map(dataid => dataid.id);
      console.log(stateId);

      const populatedCities = axios.get(`https://servicodados.ibge.gov.br/api/v1/localidades/estados/${stateId}/municipios`);
      populatedCities.then((res) => {
        setListCities(res.data);
        console.log(res.data);
      })
    })
  }, []);

  const optionsSpecies = [
    { value: '', name: 'Selecione uma espécie' },
    { value: 1, name: 'Cachorro'},
    { value: 2, name: 'Gato' },
    { value: 3, name: 'Outro' }
  ];

  const optionsPort = [
    { value: '', name: 'Selecione o porte do animal' },
    { value: 1, name: 'Pequeno'},
    { value: 2, name: 'Médio' },
    { value: 2, name: 'Grande' },
  ];

  return (
    <form>
      <div>
        <fieldset>
          <Select
            label="Espécie"
            name="species"
            options={optionsSpecies}
            value={species}
            onChange={(event) => setSpecies(event.target.value)}
            />
        </fieldset>
        <fieldset>
          <Select
            label="Porte do animal"
            name="port"
            options={optionsPort}
            value={port}
            onChange={event => setPort(event.target.value)}
          />
        </fieldset>
        <fieldset>
          <label htmlFor="states">Estado</label>
          <select value={UFs} onChange={event => {setUFs(event.target.value); console.log(event.target.selectedIndex)}} name="states">
            <option value="">Selecione um estado</option>
              {listUFs.map(listUF => (
               <option key={listUF.id}>
                  {listUF.nome}
               </option>
              ))}
          </select>
        </fieldset>
        <fieldset>
        <label htmlFor="states">Cidade</label>
          <select
            value={cities}
            onChange={event => setCities(event.target.value)}
            name="states">
            <option value="">Selecione uma cidade</option>
            {listCities.map(listCity => (
              <option key={listCity.id}>
                {listCity.nome}
              </option>
            ))}
          </select>
        </fieldset>

      </div>

      <button type="submit">Procurar</button>
    </form>

  );
};

2 answers

1

I understand your difficulty is how to make the relationship between the two <select> and I decided to develop a minimum example, showing the dynamics when choosing the unit Ederativa load the city and so on, and a toast also when starting the component already loads by default the unit Ederativa AC, example:

   
function App() {
  const [uf, setUf] = React.useState('AC');
  const [listUf, setListUf] = React.useState([]);
  const [city, setCity] = React.useState('');
  const [listCity, setListCity] = React.useState([]);
  function loadUf() {
      let url = 'https://servicodados.ibge.gov.br/';
      url = url + 'api/v1/localidades/estados';
      fetch(url)
        .then(response => response.json())
        .then(data => {        
          data.sort((a,b) => a.nome.localeCompare(b.nome));
          setListUf([...data]);
         });
  }
  function loadCity(id) {
      let url = 'https://servicodados.ibge.gov.br/api/v1/';
      url = url + `localidades/estados/${id}/municipios`;
      fetch(url)
        .then(response => response.json())
        .then(data => {        
          data.sort((a,b) => a.nome.localeCompare(b.nome));
          setListCity([...data]);
         });
  }
  React.useEffect(() => {
    loadUf();
  },[]);
  React.useEffect(() => {
    if (uf) {
      loadCity(uf);
    }
  }, [uf]);
  return (
    <div>
      <select value={uf} onChange={e => setUf(e.target.value)}>
      {listUf.map((a, b) => ( 
          <option value={a.id}>{a.sigla} - {a.nome}</option>
       ))}
      </select>
      <select value={city} onChange={e => setCity(e.target.value)}>
      {listCity.map((a, b) => ( 
          <option value={a.sigla}>{a.nome}</option>
       ))}
      </select>
    </div>
  )
}

ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

in this code has 4 states two to store the selections of the boxes and the other two to store the lists of the respective values. With two useEffect that will carry the box of Uf and the other that when changing the unit Ederativa carries the cities.

With this example you will give a way to solve your problem and note that it was done as simple as possible to understand the process.

An important factor is the naming of names, take a look at the code and realize that it is used camelCase where the first letter is lowercase and the others connected are uppercase, example: objetoSorte, sorteObjeto, etc..

0

You search cities only when the value of the state Ufs changes.

In your current code you are searching so it loads all Ufs.

useEffect(() => { searchCities() },[UFs]);

Browser other questions tagged

You are not signed in. Login or sign up in order to post.