Как хранить переменную в функциональном компоненте React?

Рейтинг: -1Ответов: 1Опубликовано: 18.01.2023

Как хранить переменную внутри реакт функционального компонента чтобы ее состояние гарантированно изменялось сразу?

Сейчас если вызвать setCount из

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

то переменная count в определенных местах остается старой.

Например setCount(5)
Затем setCount(3) 

count выводит 5, а не 3

Ответы

▲ 0Принят

Вот эмулировал поведение. Если ввести быстро 123 То через 2 секунды будет записано 1, а должно быть 123.

Потому что именно это вы и написали!

if (ev.target.value === "1") {
  setTimeout(() => {
    setCount(ev.target.value)
  }, 2000)
} else {
  setCount(ev.target.value)
}

Что происходит, когда вы быстро (менее, чем за две секунды) набираете 123:

ev.target.value = "1" Срабатывает первая ветка и запускает двухсекундный таймер по истечении которого будет вызвана setCount("1").

ev.target.value = "12" Срабатывает вторая ветка. Состояние обновляется почти мгновенно.

ev.target.value = "123" Срабатывает вторая ветка. Состояние обновляется почти мгновенно.

Приблизительно через две секунды после того, как вы набрали 1, наконец срабатывает таймер, который и вызывает setCount("1"), а не текущее значение инпута.

Вот логи (добавил в ваш пример в начало handleChange два console.log):

Hello console
input=1
count=undefined
1
input=12
count=undefined
input=123
count=12
1-1

А теперь, отвечая на ваш вопрос:

Например setCount(5) Затем setCount(3) count выводит 5, а не 3

Если вы обновляете один и тот же state два и более раз подряд, то стоит в set-функцию передавать не новое значение, а тоже ф-ю, которая принимает старое значение как аргумент и возвращает новое.

Пример:

const [count, setCount] = useState(0)

function handleChange(e) {
  setCount(count + 1)
  setCount(count + 1)
}

Ожидаемый результат: count каждый раз увеличивается на 2.

Фактический результат: count увеличивается лишь на 1.

Причина: state обновляется асинхронно. На момент вызова второго setCount count всё ещё равен предыдущему значеню. Например, если count сейчас равен 0, то дважды вызывается setCount(0 + 1).

Решение:

const [count, setCount] = useState(0)

function handleChange(e) {
  setCount((count) => count + 1)
  setCount((count) => count + 1)
}

UPD:

А как не меняя код функции handleChange добиться чтобы переменная count, имела значение 123, а не перезаписалась потом на 1 через 2 секунды?

Если вам не нужно обязательно ждать 2 секунды перед обновлением, то лучшим решением будет просто сразу обновлять состояние.

function handleChange(e) {
  setState(e.target.value) // И никаких if else
}

Если вам из соображений производительности нужно, чтобы состояние обновлялось не сразу, тогда на помощь придёт такая конструкция.

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

Проблема: запрос отправляется при каждом изменении поля. Т. е. на одно слово wood у нас будет четыре запроса на сервер: w, wo, woo, wood.

Решение: useEffect и timeout.

const [name, setName] = useState("");

useEffect(() => {
  const timeoutID = setTimeout(() => {
    // творим, что душе угодно
    console.log("api call: " + name);
  }, 500);

  // обязательно очищаем предыдущий таймер
  return () => clearTimeout(timeoutID);
}, [name]);

function handleChange(e) {
  setName(e.target.value);
}

Вот статья на эту тему: [React] Wait for User to stop typing then execute a function.

А вот документация по React.useEffect: Using the Effect Hook.