Что происходит при использовании this.setState несколько раз в компоненте React?
Я хотел проверить, что происходит, когда вы используете this.setState несколько раз (2 раза для обсуждения).
Я думал, что компонент будет отображаться дважды, но, видимо, он отображается только один раз. Еще одно ожидание: второй вызов setState будет работать над первым, но вы догадались, что он работает нормально.
Ссылка на JSfiddle
var Hello = React.createClass({
render: function() {
return (
<div>
<div>Hello {this.props.name}</div>
<CheckBox />
</div>
);
}
});
var CheckBox = React.createClass({
getInitialState: function() {
return {
alex: 0
};
},
handleChange: function(event) {
this.setState({
value: event.target.value
});
this.setState({
alex: 5
});
},
render: function() {
alert('render');
return (
<div>
<label htmlFor="alex">Alex</label>
<input type="checkbox" onChange={this.handleChange} name="alex" />
<div>{this.state.alex}</div>
</div>
);
}
});
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
Как вы увидите, на каждом рендере появляется предупреждение о том, что "render" появляется.
Есть ли у вас объяснение, почему он работал правильно?
Ответы
Ответ 1
Реагировать пакеты обновлений состояния, которые происходят в обработчиках событий и методах жизненного цикла. Таким образом, если вы обновляете состояние несколько раз в обработчике <div onClick />
, React будет ожидать завершения обработки событий перед повторным рендерингом.
Чтобы быть ясным, это работает только в обработчиках синтетических событий, управляемых с помощью реакций и методах жизненного цикла. Например, обновления состояния не обрабатываются в обработчиках событий AJAX и setTimeout
.
Ответ 2
Метод setState() не сразу обновляет состояние компонента, а просто переносит обновление в очередь для последующей обработки. React может объединить несколько запросов обновления, чтобы сделать рендеринг более эффективным. В связи с этим необходимо предпринять особые меры предосторожности при попытке обновления состояния на основе предыдущего состояния компонента.
Например, следующий код только увеличит атрибут значения состояния на 1, хотя он был вызван 4 раза:
class Counter extends React.Component{
constructor(props){
super(props)
//initial state set up
this.state = {value:0}
}
componentDidMount(){
//updating state
this.setState({value:this.state.value+1})
this.setState({value:this.state.value+1})
this.setState({value:this.state.value+1})
this.setState({value:this.state.value+1})
}
render(){
return <div>Message:{this.state.value}</div>
}
}
Чтобы использовать состояние после его обновления, выполните всю логику в аргументе обратного вызова:
//this.state.count is originally 0
this.setState({count:42}, () => {
console.log(this.state.count)
//outputs 42
})
Метод setState (updater, [callback]) может принимать функцию обновления в качестве первого аргумента для обновления состояния на основе предыдущего состояния и свойств. Возвращаемое значение функции обновления будет слабо слито с предыдущим состоянием компонента. Метод обновляет состояние асинхронно, поэтому существует обратный вызов опции, который будет вызываться после завершения состояния полностью.
Пример:
this.setState((prevState, props) => {
return {attribute:"value"}
})
Ниже приведен пример обновления состояния на основе предыдущего состояния:
class Counter extends React.Component{
constructor(props) {
super(props)
//initial state set up
this.state = {message:"initial message"}
}
componentDidMount() {
//updating state
this.setState((prevState, props) => {
return {message: prevState.message + '!'}
})
}
render(){
return <div>Message:{this.state.message}</div>
}
}