Обработка устаревшего состояния в функциональных компонентах

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

Я создал код, чтобы продемонстрировать: https://codepen.io/james-ohalloran/pen/ZdNwWQ

const Counter = () => {
  const [count, setCount] = useState(0);

  const increase = () => {
    setTimeout(() => {
      setCount(count + 1);
    },1000);
  }

  const decrease = () => {
    setTimeout(() => {
    setCount(count - 1);
    },1000)
  };
  return (
    <div className="wrapper">
      <button onClick={decrease}>-</button>
      <span className="count">{count}</span>
      <button onClick={increase}>+</button>
    </div>
  );
};

В приведенном выше примере, если вы нажмете «увеличить», а затем «уменьшить» ... вы получите -1 (я ожидал, что это будет 0). Если бы это был класс React, а не функциональный компонент, я бы предположил, что решением было бы использовать bind(this) в функции, но я не ожидал, что это будет проблемой со стрелочными функциями.


person James    schedule 15.07.2019    source источник
comment
Что вы получаете, когда вы помещаете console.log (count) над оператором return?   -  person Muljayan    schedule 15.07.2019
comment
почему вы используете setTimeout?   -  person sachin mathew    schedule 15.07.2019
comment
На самом деле я не использую setTimout в своем приложении. Я жду завершения сетевого запроса, а затем меняю список ошибок. Это просто более простой пример той же проблемы.   -  person James    schedule 15.07.2019


Ответы (2)


Это из-за использования setTimeout

Предположим, вы вызывали increase() 10 раз в секунду.

count всегда будет 0. Поскольку состояние обновляется через секунду, каждое increment(), вызываемое за секунду, будет иметь необновленный count.

Таким образом, каждый increment() будет звонить setCount(0 + 1);.

Поэтому независимо от того, сколько раз вы звоните в секунду, count всегда 1.

person bkm412    schedule 15.07.2019
comment
Да, я могу подтвердить, что это поведение, которое я наблюдаю при выходе из системы. Как бы вы предложили его реструктурировать, чтобы код в обратном вызове setTimeout мог получить доступ к новому состоянию? - person James; 15.07.2019

Ах, я нашел решение. Я не понимал, что могу ссылаться на previousState из функции установки useState: https://reactjs.org/docs/hooks-reference.html#functional-updates

person James    schedule 15.07.2019