Вот проблема: я пытаюсь вызвать 2 функции одним нажатием кнопки. Обе функции обновляют состояние (я использую хук useState). Первая функция корректно обновляет значение 1 до «нового 1», но через 1 с (setTimeout) запускается вторая функция, и она меняет значение 2 до «нового 2», НО! Он устанавливает значение 1 обратно в «1». Почему это происходит? Заранее спасибо!
import React, { useState } from "react";
const Test = () => {
const [state, setState] = useState({
value1: "1",
value2: "2"
});
const changeValue1 = () => {
setState({ ...state, value1: "new 1" });
};
const changeValue2 = () => {
setState({ ...state, value2: "new 2" });
};
return (
<>
<button
onClick={() => {
changeValue1();
setTimeout(changeValue2, 1000);
}}
>
CHANGE BOTH
</button>
<h1>{state.value1}</h1>
<h1>{state.value2}</h1>
</>
);
};
export default Test;
javascript
reactjs
react-hooks
Bartek
источник
источник
changeValue2
?useState
либо использовать вместо негоuseReducer
.const [state, ...]
и затем ссылаясь на него в установщике ... Он будет использовать одно и то же состояние все время.useState
вызова, по одному для каждой «переменной».Ответы:
Добро пожаловать в закрытие ада . Эта проблема возникает потому, что всякий раз, когда
setState
вызывается,state
получает новую ссылку на память, но функцииchangeValue1
иchangeValue2
, из-за закрытия, сохраняют старую начальнуюstate
ссылку.Раствор для обеспечения
setState
отchangeValue1
иchangeValue2
получает последнее состояние, используя функцию обратного вызова (имеющий предыдущее состояние в качестве параметра):Вы можете найти более широкое обсуждение этой проблемы закрытия здесь и здесь .
источник
Ваши функции должны быть такими:
Таким образом, вы убедитесь, что не пропустили ни одного существующего свойства в текущем состоянии, используя предыдущее состояние при запуске действия. Также, таким образом, вы избегаете необходимости управлять замыканиями.
источник
Когда
changeValue2
вызывается, начальное состояние сохраняется, поэтому состояние возвращается в исходное состояние, а затемvalue2
записывается свойство.В следующий раз, когда
changeValue2
после этого вызывается состояние{value1: "1", value2: "new 2"}
,value1
свойство перезаписывается.Вам нужна функция стрелки для
setState
параметра.источник
То, что происходит, заключается в том, что оба
changeValue1
иchangeValue2
видят состояние от рендера, в котором они были созданы , поэтому, когда ваш компонент рендерит впервые, эти 2 функции видят:Когда вы нажимаете на кнопку,
changeValue1
вызывается первым и меняет состояние на{value1: "new1", value2: "2"}
ожидаемое.Теперь, после 1 секунды,
changeValue2
вызывается, но эта функция все еще видит начальное состояние ({value1; "1", value2: "2"}
), поэтому, когда эта функция обновляет состояние следующим образом:setState({ ...state, value2: "new 2" });
вы в конечном итоге увидеть:
{value1; "1", value2: "new2"}
.источник
источник