Есть ли синхронная альтернатива 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 (который будет добавлен в конец очереди).