setState
равно asyn c, что означает, что при установке состояния в al oop у вас еще не будет обновленных значений состояния. Когда вы делаете обновления состояния на основе предыдущих значений состояния, вы должны использовать форму средства обновления setState
.
Пример того, что идет не так
class Example extends React.Component {
constructor() {
super();
this.state = {
arr: []
}
}
componentDidMount() {
[1,2,3].forEach((i) => {
// setState is async,
// so it has not updated by the next loop
// meaning its the same every cycle
console.log(this.state.arr)
this.setState({ arr: [...this.state.arr, i] });
})
}
render() {
// Only the last enty is in the array
console.log('final', this.state.arr)
return (<div>test</div>);
}
}
ReactDOM.render(<Example/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Пример правильного пути
class Example extends React.Component {
constructor() {
super();
this.state = {
arr: []
}
}
componentDidMount() {
[1,2,3].forEach((i) => {
// Use the updater form so you are guaranteed
// to have the most recent copy of state each update
this.setState((prevState) => ({ arr: [...prevState.arr, i] }));
})
}
render() {
console.log('final: ', this.state.arr)
return (<div>test</div>);
}
}
ReactDOM.render(<Example/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Еще одна функция setState
, которая может пригодиться здесь, - это вариант обратного вызова. Вы можете передать второй аргумент setState
, который является функцией. Эта функция будет вызываться после обновления состояния, поэтому вы можете добавить туда logi c в зависимости от этих обновленных значений.
class Example extends React.Component {
constructor() {
super();
this.state = {
arr: []
}
}
componentDidMount() {
[1,2,3].forEach((i) => {
this.setState((prevState) => ({ arr: [...prevState.arr, i] }), () => {
console.log('updated: ', this.state);
});
console.log('not updated: ', this.state);
})
}
render() {
return (<div>test</div>);
}
}
ReactDOM.render(<Example/>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>