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

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

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 дает? Я даже поставил задержку тайм-аута, чтобы увидеть, решило ли это проблему. какие-либо очевидные или я должен разместить больше кода?


person The worm    schedule 03.01.2017    source источник
comment
stackoverflow.com/a/36087156/4453045   -  person Assan    schedule 03.01.2017
comment
Помимо того, что сказано в ответах, вы явно регистрируете значение состояния перед вызовом setState.   -  person Felix Kling    schedule 03.01.2017
comment
@FelixKling нет, я вызываю this.state после, я его установил. Раньше я регистрировал переменную. нет?   -  person The worm    schedule 03.01.2017
comment
Из-за тайм-аута ваш setState действительно выполняется после регистрации состояния. Я думаю, что вы хотели сделать при отладке часть console.log внутри тайм-аута, а setState - снаружи.   -  person Fabian Schultz    schedule 03.01.2017
comment
@FabianSchultz, ты можешь объяснить одну вещь, которую я тогда не понимаю. рассмотрите этот код: if(this.state.playersOverallTotal > 21){ console.log('bust'); this.setState({playerBusted: true}); } когда он достигает значения более 21, журнал запускается, но состояние не изменяется, а затем изменяется только после того, как число снова увеличивается. например если бы он достиг 24, он не установил бы состояние, но затем, если бы он достиг 28, например, он бы   -  person The worm    schedule 03.01.2017
comment
Не могу воспроизвести, может задать отдельный вопрос.   -  person Fabian Schultz    schedule 03.01.2017
comment
Отвечает ли это на ваш вопрос? setState не обновляет состояние немедленно   -  person ggorlen    schedule 24.05.2021


Ответы (10)


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

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 
person Fabian Schultz    schedule 03.01.2017
comment
В дополнение к этому OP явно регистрирует значение состояния перед вызовом setState. - person Felix Kling; 03.01.2017
comment
Это работает и для меня, раньше я использовал это: `this.setState ({someVar: newValue}, function () {console.log (force update}); ', но по какой-то причине это не беспокоит больше, когда я обновил код, как описано выше, он работает. любая идея, почему? - person Jozcar; 13.07.2017
comment
@Jozcar Также должен работать, синтаксис неправильный (отсутствуют круглые скобки): this.setState({someVar: newValue},function(){ console.log("force update") }); - person Fabian Schultz; 13.07.2017
comment
imgur.com/Ku0OjTl Скажите, пожалуйста, что мне делать, чтобы избавиться от этой проблемы. - person Johncy; 01.09.2018
comment
Это не работает, если вы используете ловушку useState в функциональном компоненте. Вместо этого используйте useEffect для эффекта после рендеринга. - person Hasan Sefa Ozalp; 03.02.2020
comment
Я полностью забыл тот факт, что это асинхронный вызов, и сделал все возможные изменения кода, кроме этого, и здесь вы спасли мой мозг от выгорания. Благодарность - person Hem M; 04.11.2020

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

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

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

async changeHandler(event) {
    await this.setState({ yourName: event.target.value });
    console.log(this.state.yourName);
}
person Dev01    schedule 23.03.2019
comment
setState не возвращает обещание, поэтому я не ожидаю, что это сработает. - person ggorlen; 02.06.2021

В случае хуков вы должны использовать useEffect хук.

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

setFruit('Apple');

useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])
person Siraj Alam    schedule 13.11.2019
comment
Отлично, работает с useEffect. Но зачем он нужен? - person alex351; 09.07.2020
comment
useEffect запускается при каждом повторном рендеринге, и если элементы, переданные в массив, являются переменными состояния, изменяются. Итак, когда фрукт изменился и компонент перерисовался, этот useEffect запустится. - person Siraj Alam; 09.07.2020
comment
Я запускаю setFruit и console.log fruit вне useEffect, и они не меняются. : / - person alex351; 09.07.2020

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

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

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)
person Shubham Khatri    schedule 03.01.2017
comment
JavaScript всегда синхронен. - person Santosh Singh; 02.11.2019
comment
@santoshsingh, у вас заблуждение. Вызовы API и тайм-ауты происходят асинхронно. - person Shubham Khatri; 02.11.2019
comment
Как вы упомянули выше, javascript асинхронный --- это неверно. В основном он синхронный, а в некоторых случаях асинхронный. stackoverflow.com/questions/2035645/ - person Santosh Singh; 02.11.2019
comment
@santoshsingh. Ох, это была моя ошибка. Неправильно сформировал предложение - person Shubham Khatri; 02.11.2019
comment
очень умное использование обратного вызова для обеспечения обновления состояния перед последующим вызовом! - person user1204214; 17.11.2019

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

this.setState({ email: '[email protected]' }, () => {
   console.log(this.state.email)
)}
person Mokesh S    schedule 26.06.2020
comment
СПАСИБО, вот и все, вам нужно напрямую установить переменную - person notacorn; 12.07.2020

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

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

// Do this!
setState(prevState => {
  return {
    ...prevState,
    foo: "def"
  };
});
setState(prevState => {
  return {
    ...prevState,
    bar: 456
  };
});
person Arun Gopalpuri    schedule 07.05.2020

просто добавьте метод componentDidUpdate(){} в свой код, и он будет работать. вы можете проверить жизненный цикл react native здесь:

https://images.app.goo.gl/BVRAi4ea2P4LchqJ8

person Pravin Ghorle    schedule 24.10.2019

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

Моя проблема заключалась в том, что 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);
}

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

person zmechanic    schedule 04.06.2020
comment
Это решило мою проблему, но вместо этого я поместил setState () внутри setTimeout (). Спасибо! - person thargenediad; 04.12.2020

Помимо асинхронного характера setState, имейте в виду, что у вас могут быть конкурирующие обработчики событий, один из которых выполняет нужное вам изменение состояния, а другой немедленно отменяет его снова. Например, onClick для компонента, родительский элемент которого также обрабатывает onClick. Проверить, добавив след. Предотвратите это, используя e.stopPropagation.

person Gus T Butt    schedule 18.01.2021