Спина к спине useState не обновляет первое состояние, только второе

#javascript #reactjs #react-native #react-hooks

#javascript #reactjs #react-native #реагирующие крючки

Вопрос:

Я пытаюсь создать общую функцию, которая запускает setState дважды, однако первое setState не обновляется. Есть ли какой-нибудь способ обойти это? или как исправить эту проблему?

Родительский

 const [data, setData] = useState({});
const updateData = (key, value) => {
  console.log(key, value);
  setData({ ...data, [key]: value });
};
...
 <div>
    Num 1: {data.num1}, Num2: {data.num2}
 </div>
 <Child updateData={updateData} />
 

Дочерний элемент

 const { updateData } = props;
const onClick = () => {
  updateData("num1", 1);
  updateData("num2", 2);
};
return <button onClick={onClick}> Click here </button>
 

console.log возвращает оба вызываемых значения, но обновляется только 1 значение

пример codesandbox здесь

(После некоторого тестирования, даже вызывая оба в одной и той же родительской функции, при setData повторном вызове он все равно не будет работать (см. Simplify.js )

Ответ №1:

Хотя вы могли бы использовать обратный вызов, чтобы аргумент содержал текущее обновленное состояние, включая предыдущие установщики состояния, которые были запущены, но до того, как произошел повторный рендеринг:

 const updateData = (key, value) => {
  setData(data => ({ ...data, [key]: value }));
};
 

Если у вас ограниченное количество возможных свойств в data переменной, рассмотрите возможность использования отдельных состояний вместо этого:

 const [num1, setNum1] = useState(0);
const [num2, setNum2] = useState(0);
 
 const onClick = () => {
  setNum1(num1   1);
  setNum2(num2   2);
};
 

Комментарии:

1. Спасибо, решил это с помощью первого решения. Я отмечу вас как ответ через несколько минут, как только stackoverflow позволит мне это сделать. Также у меня было более 20 свойств, которые необходимо обновить таким образом, поэтому второе решение в этом случае для меня не работает.

Ответ №2:

setState является асинхронным, поэтому, если вы выполняете два вызова один за другим в одной и той же функции, состояние не будет обновлено для второго вызова, и вы не получите то, что хотите.

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

 const updateData = (key, value) => {
  setData(prevData => { ...prevData, [key]: value });
};

const onClick = () => {
  updateData("num1", 1);
  updateData("num2", 2);
};