export default function App() {
let [color, setColor] = useState("red");
useEffect(() => {
setColor("blue");
setTimeout(() => {
console.info(color);
setColor("purple");
}, 1000);
}, []);
function revealColor() {
console.info(color);
}
return <button onClick = {revealColor}>Click after 1 second to reveal color</button>
}
После этого предыдущего вопроса я понимаю, что обратный вызов setTimeout
ссылается на первую переменную color
(красная). Каким-то образом его setColor
удается изменить самую последнюю переменную color
(о чем свидетельствует нажатие кнопки, которая регистрирует «фиолетовый»). Как это так? Я думал, что setColor
будет так же ссылаться на старую переменную setColor
.
P.S. под «старым» я имею в виду тот факт, что setColor("blue");
повторно выполняет весь компонент, который возвращает новую color
переменную/функцию.
Это потому, что вы не включили color
в массив зависимостей useEffect
. Из-за этого useEffect
не знает, что color
изменился. Если вы включите его в массив зависимостей, то useEffect
будет срабатывать при каждом изменении color
. Таким образом, вы можете увидеть blue
, когда вы входите в систему.
useEffect(() => {
setColor("blue");
setTimeout(() => {
console.info(color);
setColor("purple");
}, 1000);
}, [color]); // <- dependency array
setColor
— это функция, которая изменяет color
в состоянии. Он не изменяет напрямую переменную color
.
Каждый раз, когда состояние изменяется, функция App
запускается повторно.
Поэтому, когда он запускается в первый раз, он вызывает useState("red")
, обнаруживает, что существующего состояния нет, устанавливает состояние в "red"
, а затем присваивает состояние ("red"
) color
. DOM обновляется с результатом.
setColor("blue");
изменяет состояние на "blue"
, что приводит к повторному запуску App
. Состояние уже есть, поэтому color
установлено на "blue"
. Он не инициализируется с помощью "red"
. DOM обновляется с результатом.
Через секунду тайм-аут разрешается, и setColor("purple");
устанавливает цвет в состоянии на "purple"
, что заставляет App
запускаться снова. Состояние уже есть, поэтому color
установлено на "purple"
.
Каждый раз, когда DOM обновляется, в revealColor
передается новая функция onClick
, которая закрывается над переменной color
из самого последнего вызова App
.
Между тем, функция, которую вы передаете useEffect
, запускается только один раз (потому что вы передали []
в качестве второго аргумента), поэтому закрытая переменная color
является исходной, и вы регистрируете "red"
там.