React中的setState()没有更新onClick状态

时间:2018-04-26 18:23:51

标签: javascript reactjs react-redux

我正在构建一个组件,该组件从按周分组的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 weekprevious week按钮时,我会遇到完全相同的事情:首先点击状态保持不变(因此发送与之前状态的API调用) ,然后它开始处理第二次点击。

经过一些研究后,我发现setState()是异步调用的,所以我将上面的代码替换为setState()引用其先前的状态,如下所示:

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

然而,这并没有解决问题,我仍然遇到同样的问题。我做错了什么?

2 个答案:

答案 0 :(得分:2)

经过几个小时的调查后,我设法找到了问题的根本原因。显然正在发生的事情是setState()迟迟未更新week州。使用较旧版本的州调用API。

为了解决这个问题,我使用了async/await

  1. 首先更新状态和await
  2. 然后调用API以获取结果。
  3. 代码现在看起来像这样:

      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()与redux thunks和其他复杂的异步函数混合时,请始终使用then()相应地将它们链接起来,甚至更简单,使用async/await语法。

答案 1 :(得分:0)

下面代码段中的下一个按钮按预期工作。其他按钮由于未定义的过程而失败。我保持尽可能接近你的代码。我不认为您的问题包含在您在问题中提供的代码中。

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>

相关问题