Есть ли синхронная альтернатива setState() в Reactjs
Согласно объяснению в документах:
setState() не сразу мутирует this.state, но создает ожидающий переход состояния. Доступ к this.state после вызова этого метода может потенциально вернуть существующее значение.
Нет гарантии синхронной работы вызовов setState, и вызовы могут быть собраны для повышения производительности.
Так как setState()
является асинхронным, и нет гарантии его синхронной производительности. Существует ли альтернатива setState()
которая является синхронной.
Например
//initial value of cnt:0
this.setState({cnt:this.state.cnt+1})
alert(this.state.cnt); //alert value:0
Так как значение alert
- это предыдущее значение, то какова альтернатива, которая даст alert value:1
с помощью setState()
.
В Stackoverflow есть несколько вопросов, которые похожи на этот вопрос, но нет, где я могу найти правильный ответ.
Ответы
Ответ 1
Как вы прочли из документации, альтернативы синхронизации НЕТ, причина, как описано, заключается в повышении производительности.
Однако я полагаю, что вы хотите выполнить действие после того, как изменили свое состояние, вы можете достичь этого с помощью:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
x: 1
};
console.log('initial state', this.state);
}
updateState = () => {
console.log('changing state');
this.setState({
x: 2
},() => { console.log('new state', this.state); })
}
render() {
return (
<div>
<button onClick={this.updateState}>Change state</button>
</div>
);
}
}
ReactDOM.render(
<MyComponent />,
document.getElementById("react")
);
<div id="react"></div>
<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>
Ответ 2
Нет, нет. React будет обновлять состояние, когда оно сочтет нужным, делая такие вещи, как setState
соединение setState
для повышения эффективности. Вам может быть интересно, что вы можете передать функцию в setState
вместо этого, которая принимает предыдущее состояние, поэтому вы можете выбрать новое состояние с хорошим знанием предыдущего.
Ответ 3
Если это необходимо, я бы предложил использовать обратный вызов в вашей функции setState (и я также предлагаю использовать функциональный setState).
Обратный вызов будет вызван после обновления состояния.
Например, ваш пример будет
//initial value of cnt:0
this.setState(
(state) => ({cnt: state.cnt+1}),
() => { alert(this.state.cnt)}
)
согласно документации здесь: https://facebook.github.io/react/docs/react-component.html#setstate
Примечание. Официальные документы говорят: "Обычно мы рекомендуем использовать для этой логики componentDidUpdate()".
Ответ 4
Короткий ответ на ваш вопрос - НЕТ, реакция не имеет метода синхронизации setState
.
Ответ 5
Да, есть метод, с помощью которого мы можем сделать наш синхронный setState. Но его производительность может быть не очень хорошей, как обычно. Например, мы имеем
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 0
};
}
changeState(){
console.log('in change state',this.state.data);
this.state.data = 'new value here'
this.setState({});
console.log('in change state after state change',this.state.data);
}
render() {
return (
<div>
<p>{this.state.data}</p>
<a onClick={this.changeState}>Change state</a>
</div>
);
}
}
В этом примере мы сначала меняем состояние, а затем выводим наш компонент.
Ответ 6
Вы можете обернуть setState в функцию, возвращающую обещание, а затем использовать эту функцию с ключевым словом await, чтобы заставить ваш код ждать, пока состояние не будет применено.
class MyComponent extends React.Component {
function setStateSynchronous(stateUpdate) {
return new Promise(resolve => {
this.setState(stateUpdate, () => resolve());
});
}
async function foo() {
// state.count has value of 0
await setStateSynchronous(state => ({count: state.count+1}));
// execution will only resume here once state has been applied
console.log(this.state.count); // output will be 1
}
}
В функции foo ключевое слово await
заставляет выполнение кода приостанавливаться до тех пор, пока обещание, возвращаемое setStateSynchronous
не будет разрешено, что происходит только после вызова обратного вызова, переданного в setState
, что происходит только после применения состояния. Таким образом, выполнение достигает вызова console.log только после применения обновления состояния.
документы для async/await:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
Ответ 7
Я смог обмануть React при вызове setState
синхронно, обернув мой код в setTimeout(() => {......this.setState({... });....}, 0);
, Поскольку setTimeout
помещает материал в конец очереди событий JavaScript, я думаю, что React обнаруживает, что setState находится внутри него, и знает, что он не может полагаться на setState
вызов setState
(который будет добавлен в конец очереди).