useState не обновляется должным образом после выбора внутри раскрывающихся списков

У меня есть функция отключения раскрывающегося списка, пока не будет сделан выбор в двух других раскрывающихся списках. Я считаю, что это не позволяет правильно раскрыть раскрывающийся список из-за некоторых асинхронных проблем с useState.

const [homeSelect, setHomeSelect] = useState('Home');
const [hedgeSelect, setHedgeSelect] = useState('Hedge');
const [symbolSelect, setSymbolSelect] = useState('1');

const handleHome = (event) => {
    setHomeSelect(event.target.value);
    exchange_change();
  };
const handleHedge = (event) => {
  setHedgeSelect(event.target.value);
  exchange_change();
};
const handleSymbol = (event) => {
  setSymbolSelect(event.target.value);
};

const exchange_change = () => {
  if (homeSelect != 'Home' && hedgeSelect != 'Hedge'){
    //enable the symbol dropdown
      setDisabled(false);
  } else {
      //disable the select exchanges dropdown
      setDisabled(true);
  }
}
<FormControl dense>
  <TextField
    id="standard-select-currency"
    select
    label="Home"
    className={classes.textField}
    value={homeSelect}
    onChange={handleHome}
    SelectProps={{
      native: true,
    }}
    helperText="Please select exchange"
  >
    {home.map((option) => (
      <option key={option.value} value={option.value}>
        {option.label}
      </option>
    ))}
  </TextField>
</FormControl>

<FormControl dense>
  <TextField
    id="standard-select-currency"
    select
    label="Hedge"
    className={classes.textField}
    value={hedgeSelect}
    onChange={handleHedge}
    SelectProps={{
      native: true,
    }}
    helperText="Please select exchange"
  >
    {hedge.map((option) => (
      <option key={option.value} value={option.value}>
        {option.label}
      </option>
    ))}
  </TextField>
</FormControl>

<FormControl dense>
  <TextField
    id="standard-select-currency"
    select
    label="Symbols"
    className={classes.textField}
    value={symbolSelect}
    onChange={handleSymbol}
    disabled={disabled}
    SelectProps={{
      native: true,
    }}
    helperText="Please select the exchanges"
  >
    {symbols.map((option) => (
      <option key={option.value} value={option.value}>
        {option.label}
      </option>
    ))}
  </TextField>
</FormControl>

Выпадающие home и hedge требуют выбора перед включением раскрывающегося symbol. Ошибка: symbol раскрывающийся список не будет активирован до тех пор, пока home и hedge не будут выбраны более одного раза.

Как я могу изменить методы, которые я использую, чтобы вместо этого использовать useReducer (если это решит проблему обновления состояния)? Я пробовал читать об этом, но не понимаю, какие у меня будут корпуса переключателей.

Любая помощь приветствуется, спасибо.


person Zero Cool    schedule 03.11.2020    source источник


Ответы (1)


Операции над наборами являются асинхронными. Итак, когда вы это сделаете:

setHomeSelect(event.target.value);
exchange_change();

Пока вызывается этот второй вызов метода, переменная homeSelect не изменилась. Это изменится, когда логика завершится, и компонент подготовится к повторному рендерингу.

Более того, это не очень похоже на React:

const exchange_change = () => {
  if (homeSelect != 'Home' && hedgeSelect != 'Hedge'){
    //enable the symbol dropdown
    setDisabled(false);
  } else {
    //disable the select exchanges dropdown
    setDisabled(true);
  }
}

Пока вы изменяете здесь значение состояния, концептуально кажется, что вы пытаетесь изменить пользовательский интерфейс. Не надо. Компоненты пользовательского интерфейса могут просто реагировать на состояние. Поэтому вместо этого метода вы можете сделать это в своем компоненте Symbols:

disabled={homeSelect == 'Home' || hedgeSelect == 'Hedge'}

Если вы хотите поместить это в метод, поместите его в тот, который вызывается компонентом, а не вызывается перед повторным рендерингом. Например:

disabled={() => checkSelects()}

И этот метод может быть:

const checkSelects = () => 
  homeSelect == 'Home' || hedgeSelect == 'Hedge';

Но в целом просто помните о порядке действий здесь. Выполняется вся логика, вызываемая событием пользовательского интерфейса, которое ставит в очередь обновления состояния. Затем состояние обновляется. Затем компоненты повторно визуализируются (при необходимости). Не полагайтесь на обновление состояния во время этой логики.

person David    schedule 03.11.2020
comment
Имеет смысл, но так странно. Зачем React читать setHomeSelect(event.target.value); exchange_change(); и ждать, пока функция не выполнит изменение состояния? Кажется, очень сбивает с толку разработчиков - person Zero Cool; 03.11.2020