React setState не обновляет состояние


99

Итак, у меня есть это:

let total = newDealersDeckTotal.reduce(function(a, b) {
  return a + b;
},
0);

console.log(total, 'tittal'); //outputs correct total
setTimeout(() => {
  this.setState({dealersOverallTotal: total});
}, 10);

console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1'); //outputs incorrect total

newDealerDeckTotal - это просто массив чисел, [1, 5, 9]например, но this.state.dealersOverallTotalне дает правильной суммы, но totalдает? Я даже поставил задержку тайм-аута, чтобы увидеть, решило ли это проблему. какие-нибудь очевидные или я должен разместить больше кода?



@Assan ура !!
Червь

Помимо того, что сказано в ответах, вы явно регистрируете значение состояния перед вызовом setState.
Феликс Клинг

1
@FelixKling нет, я вызываю this.state после того, как установил его. Раньше я регистрировал переменную. нет?
Червь

Из-за тайм-аута ваш setStateдействительно выполняется после регистрации состояния. Я думаю, что вы имели в виду при отладке поместить console.logчасть внутрь таймаута и setStateснаружи.
Фабиан Шульц

Ответы:


192

setState()обычно является асинхронным, что означает, что на момент console.logсоздания состояния оно еще не обновлено. Попробуйте поместить журнал в обратный вызов setState()метода. Он выполняется после завершения изменения состояния:

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 

2
В дополнение к этому OP явно регистрирует значение состояния перед вызовом setState.
Феликс Клинг

Это работает и для меня, раньше я использовал это: `this.setState ({someVar: newValue}, function () {console.log (" force update}); 'но по какой-то причине это не беспокоило больше, когда я обновил код, как описано выше, он работает.
Есть

1
@Jozcar Должен также работать, синтаксис был неправильным (отсутствовали круглые скобки):this.setState({someVar: newValue},function(){ console.log("force update") });
Fabian Schultz

imgur.com/Ku0OjTl Подскажите, пожалуйста, что мне делать, чтобы избавиться от этой проблемы.
Johncy 01

1
Я полностью забыл тот факт, что это асинхронный вызов, и сделал все возможные изменения кода, кроме этого, и здесь вы спасли мой мозг от выгорания. спасибо
Hem M

17

setState является асинхронным. Вы можете использовать метод обратного вызова, чтобы получить обновленное состояние.

changeHandler(event) {
    this.setState({ yourName: event.target.value }, () => 
    console.log(this.state.yourName));
 }

12

Использование async / await

async changeHandler(event) {
    await this.setState({ yourName: event.target.value });
    console.log(this.state.yourName);
}

8

setState()Операция асинхронная и , следовательно , ваш console.log()будет выполняться до setState()мутирует значения и , следовательно , вы видите результат.

Чтобы решить эту проблему, зарегистрируйте значение в функции обратного вызова setState(), например:

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)

JavaScript всегда синхронен.
Сантош Сингх

1
@santoshsingh, у вас заблуждение. Вызовы API и тайм-ауты происходят асинхронно.
Шубхам Хатри

Как вы упомянули выше, javascript является асинхронным --- это неверно. В основном он синхронный, а в некоторых случаях асинхронный. stackoverflow.com/questions/2035645/…
Сантош Сингх

@santoshsingh. Ох, это была моя ошибка. Неправильно сформировал приговор
Шубхам Хатри

очень умное использование обратного вызова для обеспечения обновления состояния перед последующим вызовом!
user1204214

7

В случае крючков следует использовать useEffectкрючок.

const [fruit, setFruit] = useState('');

setFruit('Apple');

useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])

Отлично, работает с useEffect. Но зачем он нужен?
alex351 09

useEffectвыполняется при каждом повторном рендеринге, и если элементы, переданные в массив, являются переменными состояния, песком изменяются. Итак, когда фрукт изменится и компонент будет повторно отрисован, этот useEffect запустится.
Сирадж Алам

Я запускаю setFruit и console.log fruit вне useEffect, и он не меняется. : /
alex351 09

4

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

введите описание изображения здесь

Приведенный ниже метод «не рекомендуется», но для понимания, если вы изменяете состояние напрямую, вы можете увидеть обновленное состояние в следующей строке. Повторяю, это «не рекомендуется»

введите описание изображения здесь


СПАСИБО, вот и все, вы должны напрямую установить переменную
notacorn


1

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

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

Проще говоря, у меня что-то вроде этого:

render() {
    <Control
        ref={_ => this.control = _}
        onChange={this.handleChange}
        onUpdated={this.handleUpdate} />
}

handleChange() {
    this.control.doUpdate();
}

handleUpdate() {
    this.setState({...});
}

Как я должен был «исправить» это было положить doUpdate()в setTimeoutтак:

handleChange() {
    setTimeout(() => { this.control.doUpdate(); }, 10);
}

Не идеально, но в противном случае это был бы значительный рефакторинг.


Это решило мою проблему, но вместо этого я поместил setState () внутри setTimeout (). Спасибо!
thargenediad

0

У меня возникла проблема при настройке состояния реакции несколько раз (всегда использовалось состояние по умолчанию). После этой проблемы с реакцией / github у меня сработало

const [state, setState] = useState({
  foo: "abc",
  bar: 123
});

// Do this!
setState(prevState => {
  return {
    ...prevState,
    foo: "def"
  };
});
setState(prevState => {
  return {
    ...prevState,
    bar: 456
  };
});
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.