ReactJS setState не работает с параметром / аргументом из метода / функции

Кажется, я не могу заставить setState изменить (мутировать) значение, исходящее из аргумента или параметра метода / функции. По крайней мере, при первом звонке не работает. Мне нужно дважды вызвать setState, прежде чем значение изменится.

import React from 'react'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      testItem: 'originalValue'
    }
  }

  updateState(input) {
    this.setState({
      testItem: input
    },
      console.log(this.state.testItem) // displays 'originalValue' instead of 'newValue!', at least on the first call
    )
  }

  render() {
    return (
      <button onClick={() => this.updateState('newValue!')}>
        Change State
        </button>
    )
  }
}

export default App

Состояние testItem должно измениться с originalValue на newValue! (берется из аргумента input в методе updateState (input)) при нажатии кнопки, но не изменяется при первом щелчке (даже при использовании обратного вызова в setState). Он меняется только тогда, когда я нажимаю на кнопку второй раз. Почему это?


person matic    schedule 06.10.2019    source источник


Ответы (3)


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

Из-за этого нам нужно отложить вызов console.log, заключив его в функцию. Мы делаем это, чтобы он мог быть вызван позже setState, а не каждый раз, когда вы вызываете setState

Для этого вы передаете функцию обратного вызова, которая будет выполнена после выполнения вашего setState.

this.setState({ testItem: input}, () => console.log(this.state))
person Paul McLoughlin    schedule 06.10.2019
comment
Ах, забыл () = ›в обратном вызове! Ошибка новичка. Спасибо за вашу помощь! - person matic; 06.10.2019
comment
Ха, нет проблем, если я ответил на ваш вопрос, примите его как ответ - person Paul McLoughlin; 06.10.2019

Это происходит потому, что setState асинхронный. Вы можете использовать обратный вызов или async-await. Решение обратного вызова уже предоставлено. Я хотел бы дать решение с помощью async-await -

async updateState(input) {
    await this.setState({
      testItem: input
    });
    console.log(this.state.testItem);
}
person urvashi    schedule 06.10.2019
comment
Спасибо за этот ответ, который дополняет решение обратного вызова. - person matic; 08.10.2019

Это произошло потому, что перед обновлением состояния был запущен console.log(this.state.testItem). As setState по своей природе асинхронный. Во избежание этого:

  1. Решение для взлома - используйте setTimeout (дождитесь обновления)
   updateState(input) {
    this.setState({
      testItem: input
    });
    setTimeOut (() => {
      console.log(this.state.testItem)
    }) 
  }
  1. Предпочтительный способ - передать обратный вызов в качестве второго параметра
   updateState(input) {
    this.setState({
      testItem: input
    }, () => console.log(this.state.testItem))
   }
person javasctipt nerd    schedule 06.10.2019