Почему вызов метода setState не изменяет состояние сразу?
Хорошо, я постараюсь сделать это быстро, потому что это должно быть легко исправить...
Я прочитал кучу похожих вопросов, и ответ кажется вполне очевидным. Ничего, что мне бы никогда не пришлось искать в первую очередь! Но... У меня ошибка, которую я не могу понять, как исправить или почему это происходит.
Следующее:
class NightlifeTypes extends Component {
constructor(props) {
super(props);
this.state = {
barClubLounge: false,
seeTheTown: true,
eventsEntertainment: true,
familyFriendlyOnly: false
}
this.handleOnChange = this.handleOnChange.bind(this);
}
handleOnChange = (event) => {
if(event.target.className == "barClubLounge") {
this.setState({barClubLounge: event.target.checked});
console.log(event.target.checked)
console.log(this.state.barClubLounge)
}
}
render() {
return (
<input className="barClubLounge" type='checkbox' onChange={this.handleOnChange} checked={this.state.barClubLounge}/>
)
}
Больше кода окружает это, но здесь моя проблема. Должно работать, верно?
Я также попробовал это:
handleOnChange = (event) => {
if(event.target.className == "barClubLounge") {
this.setState({barClubLounge: !this.state.barClubLounge});
console.log(event.target.checked)
console.log(this.state.barClubLounge)
}
Итак, у меня есть эти два console.log()
х, оба должны быть одинаковыми. Я буквально устанавливаю состояние так же, как event.target.checked
в строке выше этого!
Но это всегда возвращает противоположность того, что должно.
То же самое касается, когда я использую !this.state.barClubLounge
; Если он запускается как false, при первом щелчке он остается false, даже если флажок установлен или нет, зависит от состояния!!
Это безумный парадокс, и я понятия не имею, что происходит, пожалуйста, помогите!
3 ответа
Причина setState является асинхронной, вы не можете ожидать обновления state
значение сразу после setState
, если вы хотите проверить значение, используйте callback
метод. Передайте метод в качестве обратного вызова, который будет выполнен после setState
завершить свою задачу.
Почему setState является асинхронным?
Это потому что setState
изменяет state
и вызывает повторную визуализацию. Это может быть дорогостоящей операцией и сделать это synchronous
может оставить браузер без ответа. Таким образом setState
звонки asynchronous
а также пакет для лучшего опыта и производительности пользовательского интерфейса.
Из Док:
setState () не изменяет немедленно this.state, но создает ожидающий переход в состояние. Доступ к this.state после вызова этого метода может потенциально вернуть существующее значение. Нет гарантии синхронной работы вызовов setState, и вызовы могут быть пакетированы для повышения производительности.
Используя метод обратного вызова с setState:
Чтобы проверить обновленный state
значение сразу после setState
, используйте метод обратного вызова, как это:
setState({ key: value }, () => {
console.log('updated state value', this.state.key)
})
Проверь это:
class NightlifeTypes extends React.Component {
constructor(props) {
super(props);
this.state = {
barClubLounge: false,
seeTheTown: true,
eventsEntertainment: true,
familyFriendlyOnly: false
}
}
handleOnChange = (event) => { // Arrow function binds `this`
let value = event.target.checked;
if(event.target.className == "barClubLounge") {
this.setState({ barClubLounge: value}, () => { //here
console.log(value);
console.log(this.state.barClubLounge);
//both will print same value
});
}
}
render() {
return (
<input className="barClubLounge" type='checkbox' onChange={this.handleOnChange} checked={this.state.barClubLounge}/>
)
}
}
ReactDOM.render(<NightlifeTypes/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>
Поскольку setState является асинхронной функцией. Это означает, что после вызова setState переменная состояния не изменяется немедленно. Поэтому, если вы хотите выполнить другие действия сразу после изменения состояния, вы должны использовать метод обратного вызова setstate внутри вашей функции обновления setState.
handleOnChange = (event) => {
let inputState = event.target.checked;
if(event.target.className == "barClubLounge") {
this.setState({ barClubLounge: inputState}, () => { //here
console.log(this.state.barClubLounge);
//here you can call other functions which use this state
variable //
});
}
}
Это из-за соображений производительности. setState в React - это функция, гарантирующая повторную визуализацию компонента, которая является дорогостоящим процессом ЦП. Таким образом, его разработчики хотели оптимизировать, собрав несколько действий рендеринга в одно, поэтому setState является асинхронным.
Сахар,
Я использую рендер крюк в целом. Потому что позже мы можем легко удалить строку консоли:
render() {
console.log(this.state) // this runs whenever the state changes