setState () в React не обновляет состояние onClick - PullRequest
0 голосов
/ 26 апреля 2018

Я создаю компонент, который отображает данные из хранилища Redux, сгруппированного по неделям. Поскольку неделя относится только к этому компоненту, я сохраняю ее значение в качестве локального состояния следующим образом:

  constructor(props) {
    super(props);
    this.state = {
      page: 0,
      week: this.getWeekNumber(new Date())[1],
      year: this.getWeekNumber(new Date())[0]
    };
  }

Это обычно то, что я делаю в своих компонентах, и у меня никогда не было проблем с этим подходом. У меня есть три кнопки для повторного рендеринга данных на основе недели:

...
render() {
...
       <Button onClick={() => this.handleRenderWeek("previous")}>
          Previous Week
        </Button>
        <Button onClick={() => this.handleRenderWeek("current")}>
          Current Week
        </Button>
        <Button onClick={() => this.handleRenderWeek("next")}>Next Week</Button>
...

Вспомогательная функция, которая обрабатывает рендер, определяется следующим образом:

  handleRenderWeek = action => {
    const { week, year, page } = this.state;
    switch (action) {
      case "previous":
        this.setState({
          page: 0,
          week: week - 1,
          year
        });
        break;
      case "current":
        this.setState({
          page: 0,
          week: this.getWeekNumber(new Date())[1],
          year: this.getWeekNumber(new Date())[0]
        });
        break;
      case "next":
        this.setState(prevState => ({ week: prevState.week + 1 }));
        break;
      default:
        this.setState({
          page: 0,
          week: this.getWeekNumber(new Date())[1],
          year: this.getWeekNumber(new Date())[0]
        });
        break;
    }
    this.props.fetchCalendarsAndBookings(week, year, page);
  };

Проблема в том, что когда я нажимаю кнопку next week, состояние week остается прежним. Это только увеличивается, когда я делаю второй щелчок. Когда я снова третий, четвертый и т. Д. Раз, он продолжает правильно увеличиваться.

Когда я нажимаю на кнопки current week и previous week, следуя вышеизложенному, я испытываю ту же самую вещь: сначала щелчок состояние остается прежним (следовательно, отправка вызова API с предыдущим состоянием), а затем он начинает работать со второго клика вперед.

После некоторых исследований я обнаружил, что setState() вызывается асинхронно, поэтому я заменил приведенный выше код, чтобы setState() ссылался на его предыдущее состояние следующим образом:

this.setState((prevState, props) => {
            return {
              week: prevState.week + 1
            };
          }); 

Однако это не устранило проблему, и у меня все еще остается та же проблема. Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

Так что после нескольких часов исследований мне удалось найти причину проблемы. Очевидно, что происходило то, что setState() обновлял состояние week с опозданием. API вызывался со старой версией состояния.

Чтобы решить эту проблему, я использовал async/await:

  1. Сначала обновите состояние и await
  2. Затем вызовите API для получения результатов.

Код теперь выглядит примерно так:

  handleRenderWeek = async action => {
    switch (action) {
      case "previous":
        await this.decrementWeek();
        break;
      case "current":
        await this.resetWeek();
        break;
      case "next":
        await this.incrementWeek();
        break;
      default:
        await this.resetWeek();
        break;
    }
    console.log("Updated State: ", this.state.week);
    await this.props.fetchCalendarsAndBookings(
      this.state.week,
      this.state.year,
      this.state.page
    );
  };

Кардинальных уроков здесь два:

  1. setState() - асинхронная функция. Большой Ву.
  2. При смешивании setState() с редукциями и другими сложными асинхронными функциями всегда объединяйте их в цепочку с помощью then() или даже проще, используя синтаксис async/await.
0 голосов
/ 26 апреля 2018

Следующая кнопка во фрагменте ниже работает, как и ожидалось. Другие кнопки не работают из-за неопределенных процедур. Я держал это как можно ближе к вашему коду. Я не думаю, что ваши проблемы содержатся в коде, который вы предоставляете в своем вопросе.

class Hello extends React.Component {

	constructor(props) {
  	super(props);
    this.state = {
    	week: 0
    };
  }
  
  handleRenderWeek(action) {
    const { week, year, page } = this.state;
    switch (action) {
      case "previous":
        this.setState({
          page: 0,
          week: week - 1,
          year
        });
        break;
      case "current":
        this.setState({
          page: 0,
          week: this.getWeekNumber(new Date())[1],
          year: this.getWeekNumber(new Date())[0]
        });
        break;
      case "next":
        this.setState(prevState => ({ week: prevState.week + 1 }));
        break;
      default:
        this.setState({
          page: 0,
          week: this.getWeekNumber(new Date())[1],
          year: this.getWeekNumber(new Date())[0]
        });
        break;
    }
  }

  render() {
    return (
    	<div>
        <div>Hello {this.props.name}, week is {this.state.week}</div>
        <button onClick={() => this.handleRenderWeek("previous")}>
          Previous Week
        </button>
        <button onClick={() => this.handleRenderWeek("current")}>
          Current Week
        </button>
        <button onClick={() => this.handleRenderWeek("next")}>Next Week</button>
      </div>
    );
  }
}

ReactDOM.render(
  <Hello name="World" />,
  document.getElementById('container')
);
<script src="//unpkg.com/react@16/umd/react.development.js"></script>
<script src="//unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="container"></div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...