Вот эмулировал поведение. Если ввести быстро 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.