简体   繁体   中英

React <select> automatic change does not trigger onChange

In my page, I have two <select> elements, where the options of the second one depends on the value of the first one.

In this case, the "problem" is that the options for a certain value in the first select are different from the options given when the first select has another value. Basically:

  • Alfa Romeo
    • Giulietta
    • Mito
  • Porsche
    • Cayenne
    • 911

I've created a simple fiddle just to show you the example, and the problem: https://codesandbox.io/s/select-autochange-7bfj6

Please, open the console to see what I'm talking about. So, basically, at start 'Porsche' and '911' are selected. Then, if I change '911' to 'Cayenne' everything is good.

The problem is when I change 'Porsche' to 'Alfa' : as it should be, the second select changes its value to 'Giulietta' , BUT the onChange event of the second select is not triggered.
I'm mostly sure that the problem is some kind of de-synchronization between UI and state: in the state, the secondselect still has the value '911' , but since that option is no longer available in the second select, it autoselect the first possible value.. But that autoselection is just "graphical".

I know this could be fixed by adding a "null" value in the second select, with the option <option value={''} label={'Select a Model'} /> . But I'd like to mantain the autoselection when the first select changes.

EDIT: actually, the fix I proposed is not an actual fix: that 'select a Model' options has the value '' , but the handleSelectSelectChange is still not triggered, so, while the UI selected value is '' , in the state I still have '911'

 React.useEffect(()=> {
    if (!secondOptionsMemoized.some(x=> x === secondSelectValue)) {
      console.log('Second Select Change in useEffect');
      setSecondSelectValue(secondOptionsMemoized[0]);
    }
 }, [secondSelectValue, secondOptionsMemoized]);

You can use useEffect instead of useMemo and another state which set the second options:

import React, { useEffect } from "react";
import "./styles.css";

export default function App() {
  const alfaForSecondOptions = ["Giulietta", "Mito"];
  const otherForSecondOptions = ["Cayenne", "911"];

  const [firstSelectValue, setFirstSelectValue] = React.useState("Porsche");
  const [secondSelectValue, setSecondSelectValue] = React.useState("911");
  const [secondOptions, setSecondOptions] = React.useState(
    otherForSecondOptions
  );

  useEffect(() => {
    console.log(secondSelectValue);
  }, [secondOptions]);

  useEffect(() => {
    if (firstSelectValue === "Alfa") {
      setSecondOptions(alfaForSecondOptions);
      setSecondSelectValue("Giulietta");
    } else {
      setSecondOptions(otherForSecondOptions);
      setSecondSelectValue("911");
    }
  }, [firstSelectValue]);

  const handleFirstSelectChange = (e) => {
    console.log("First Select Change", e.target.value);
    setFirstSelectValue(e.target.value);
  };

  const handleSecondSelectChange = (e) => {
    console.log("Second Select Change", e.target.value);
    setSecondSelectValue(e.target.value);
  };

  return (
    <div className="App">
      <label>
        <p>Brand</p>
        <select onChange={handleFirstSelectChange} value={firstSelectValue}>
          <option value={"Alfa"} label={"Alfa"} />
          <option value={"Porsche"} label={"Porsche"} />
        </select>
      </label>

      <label>
        <p>Model</p>
        <select onChange={handleSecondSelectChange} value={secondSelectValue}>
          {secondOptions.map((x) => {
            return <option key={x} value={x} label={x} />;
          })}
        </select>
      </label>
    </div>
  );
}

编辑选择自动更改(分叉)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM