Непрерывный setState не работает должным образом

У меня есть фрагмент кода ниже -

class Sum extends React.Component {
    constructor(props) {
      super(props)
      this.state = { a : 0 }
    }

    // let's call this ADD-1
    add = () => {
      this.setState({ a: this.state.a + 1 })
      this.setState({ a: this.state.a + 2 })
      this.setState({ a: this.state.a + 3 })
    } 

    render() {
      return (<div>
        <button onClick = {this.add}> click me  </button>
        <div> sum  {this.state.a} </div>
      </div>)
    }
}

это отображается при нажатии кнопки

sum = 3

где, как я надеялся, он отобразит sum = 6, т.е. 1 + 2 + 3

Кроме того, если я изменю свой метод add на что-то вроде приспособления к условиям гонки prevState -

  // let's call this ADD-2
  add = () => {
    this.setState({ a: this.state.a + 1 })
    this.setState({ a: this.state.a + 2 })
    this.setState(prevState => ({ a: prevState.a + 1 }))
    this.setState(prevState => ({ a: prevState.a + 4 }))
  }

он отображает sum = 7, тогда как я надеялся на sum = 8, т.е. (1 + 2 + 1 + 4)

На ум приходят два вопроса:

1) Почему мы видим результаты, указанные выше, а не те, которых я ожидал?

2) Почему я не вижу перехода добавления в UI? Скажем, если мы рассмотрим метод с тегом ADD-1, я должен увидеть что-то вроде sum = 1, затем sum = 3, затем sum = 6. Это из-за пакетирования обновлений, но пакетирование помещает их в очередь выполнения, на мой взгляд, это ничего не отменяет.

setState является асинхронным, все они вызываются "по существу" сразу. Это означает, что последний устанавливает состояние на 0 + 3. Метод setState имеет обратный вызов, если вы хотите дождаться его обновления, затем вызовите другой метод setState. this.setState ({значение: значение + 1}, () => {this.setState ({значение: значение + 2})}) medium.com/@wereHamster/…

Budhead2004 29.06.2018 16:37
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
884
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

«React может объединять несколько вызовов setState () в одно обновление для повышения производительности».

От Документы

Убедитесь, что вы передаете функцию в setState, когда ваше обновление зависит от текущего состояния, чтобы оно не было перезаписано последующим setState.

Пример

class App extends React.Component {
  state = { a: 0 };

  add = () => {
    this.setState(previousState => {
      return { a: previousState.a + 1 };
    });
    this.setState(previousState => {
      return { a: previousState.a + 2 };
    });
    this.setState(previousState => {
      return { a: previousState.a + 3 };
    });
  };

  render() {
    return (
      <div>
        <button onClick = {this.add}> click me </button>
        <div> sum {this.state.a} </div>
      </div>
    );
  }
}
Ответ принят как подходящий

Обновление состояния может быть асинхронным. Отметьте это отвечать.

В отвечать Дэна Абрамова указано, что обновления состояния в рамках одного вызова события будут производить только один повторный рендеринг в конце события.

no matter how many setState() calls in how many components you do inside a React event handler, they will produce only a single re-render at the end of the event.

А также пакетирование происходит только для обновлений состояния в обработчике событий React, т.е. пакетирование не происходит внутри вызовов AJAX.

promise.then(() => {
  // We're not in an event handler, so these are flushed separately.
  this.setState({a: true}); // Re-renders with {a: true, b: false }
  this.setState({b: true}); // Re-renders with {a: true, b: true }
  this.props.setParentState(); // Re-renders the parent
});

Но вы можете добиться того, чего хотите, передав обратный вызов методу setState.

add = () => {
      this.setState({ a: this.state.a + 1 },
        () => {
        this.setState({ a: this.state.a + 2 },
          () => {
          this.setState({ a: this.state.a + 3 })
        })
      })    
    }

Вышеупомянутое вернет sum = 6.

Когда не использовать обратные вызовы в setState:

PureComponent and shouldComponentUpdate can be used to tune up a component’s performance. They work by preventing lifecycle methods from firing when props and state haven’t changed.

The setState callback fires regardless of what shouldComponentUpdate returns. So, the setState callback will fire, even when state hasn’t changed.

изменение состояния может произойти только через setState, но если вы получите доступ и измените this.state до setState (this.state.a + 1), это не отразится. поэтому каждый раз, когда вы обращаетесь к this.state.a, он получает 0, т.е. начальное значение.

add = () => {
  this.setState({ a: this.state.a + 1 }) // 0 + 1
  this.setState({ a: this.state.a + 2 }) // 0 + 2
  this.setState({ a: this.state.a + 3 }) // 0 + 3
} 

this.setState((previousState) => { // change state using previousState} );

это способ обновить состояние

Другие вопросы по теме