Update a select's options based on another dropdown, using React

Viewed 4192

I've got 2 selects in my form. Options for the 2nd select are generated based on 1st select. Everything works fine except that every time I choose an option for the 2nd select and then change the 1st one, I should get the default option for the 2nd, but it's not resetting.

enter image description here enter image description here enter image description here enter image description here

Code below

  const [animalClass, setAnimalClass] = useState();
  const [animalType, setAnimalType] = useState();

  const [isLoadingClasses, setLoadingClasses] = useState(true);
  const [isLoadingTypes, setLoadingTypes] = useState(true);
  const [availableAnimalClasses, setAvailableAnimalClasses] = useState();
  const [availableAnimalTypes, setAvailableAnimalTypes] = useState();
 
  useEffect(() => {
    setLoadingClasses(true);
    const availableOptions = async () => {
      const availableClasses = await Axios.get();
      console.log(availableClasses.data);
      if (availableClasses.data.length > 0) {
        setAvailableAnimalClasses(availableClasses.data.map(animal => ({name: animal.name})));
        setLoadingClasses(false);
      }
    };
    availableOptions();
  }, []);

  useEffect(() => {
    setLoadingTypes(true);
    setAnimalType("DEFAULT");
    const availableOptions = async () => {
      const availableTypes = await Axios.get();
      console.log(availableTypes.data);
      if(availableTypes.data.length > 0) {
        setAvailableAnimalTypes(availableTypes.data.map(animal => ({name: animal.name})));
        setLoadingTypes(false);
      }
    };
    availableOptions();
  }, [animalClass]);

  return (
    <div className="page">
    <h2>New Auction</h2>
    <form className="form" onSubmit={onSubmit}>
      <label>
      Animal Class
        <select defaultValue={'DEFAULT'} onChange={(e) => setAnimalClass(e.target.value)} >
          <option value="DEFAULT" disabled>Choose animal class</option>
          {isLoadingClasses ? <option value="Loading" disabled>Loading.....</option> :  availableAnimalClasses.map((option) => (
            <option value={option.name}>{upperCase(option.name)}</option>
          ))}
        </select>
      </label>
      <label>Animal Type
        <select defaultValue={'DEFAULT'} onChange={(e) => setAnimalType(e.target.value)} >
          <option value="DEFAULT" disabled>Choose animal type</option>
          {isLoadingTypes? <option value="Loading" disabled>Loading.....</option> :  availableAnimalTypes.map((option) => (
            <option value={option.name}>{upperCase(option.name)}</option>
          ))}
        </select>
2 Answers

Since you are using state to store your form field values, you could set your defaults when you create the hooks:

const [animalClass, setAnimalClass] = useState('DEFAULT');
const [animalType, setAnimalType] = useState('DEFAULT');

and then use value instead of defaultValue in your JSX:

<select value={animalClass} onChange={(e) => setAnimalClass(e.target.value)} >
...
<select value={animalType} onChange={(e) => setAnimalType(e.target.value)} >

These values should reset your select elements when the state changes.

You should call setAnimalType to reset it back to the default when selecting the animal class. Change:

<select defaultValue={'DEFAULT'} onChange={(e) => setAnimalClass(e.target.value)}>...</select>

...to:

<label>
  Animal Class
  <select
    defaultValue={'DEFAULT'}
    value={animalClass}
    onChange={(e) => {
      setAnimalClass(e.target.value);
      setAnimalType('DEFAULT');
    }}
  >
    ...
  </select>
</label>
<label>
  Animal Type
  <select
    defaultValue={'DEFAULT'}
    value={animalType}
    onChange={(e) => setAnimalType(e.target.value)}
  >
    // ...
  </select>
</label>

This is necessary because the onChange event will not be automatically fired for a select when the options change. In order for this to work, where state controls the state of your <select/>s, you'll also want to change the defaultValueprops tovalue` props.

Related