Помещение console.log
в функцию increment
показывает ошибку:
const increment = (i: number) => {
let newCount = [...counter];
// log values here
console.log(i, counter)
newCount[i] += 1;
setCounter(newCount);
}
Журнал читает:
"0, [0, 0, 0]"
"1, [0, 0, 0]"
"2, [0, 0, 0]"
Значение counter
всегда [0, 0, 0]
. Это вызвано замыканиями .
Когда вы вызываете setTimeout(() => increment(i), 1000)
для каждого из значений в [0, 1, 2]
, JavaScript создает в памяти три функции:
() => increment(0)
() => increment(1)
() => increment(2)
Эти функции будут выполняться через 1 секунду.
Однако, поскольку для них необходимо использовать функцию increment
, функция increment
также «копируется» в память.
* Функция 1026 * также использует переменную counter
, поэтому переменная counter
также копируется в память - ее текущее значение [0, 0, 0]
.
Это значение, которое будет используется во всех трех функциях.
Вот почему вы видите только последнее приращение значения, потому что вы, по сути, делаете это:
setCounter([1, 0, 0])
setCounter([0, 1, 0])
setCounter([0, 0, 1])
Одним из решений было бы не используйте setTimeout
вообще, , но более надежным решением является предоставление функции обратного вызова для setCounter
:
const increment = (i: number) => {
setCounter(prev => {
let newCount = [...prev]
newCount[i] += 1
return newCount
})
}
Правило состоит в том, если новые значения состояния зависят от старое значение состояния (например, при увеличении числа новое значение определяется старым значением), то вы sh может передать обратный вызов для установки состояния.
Вы не можете полагаться на counter
как актуальное значение.
См. D. Ответ Смита для некоторых полезных ссылок, связанных с замыканиями и setTimeout
.