我正在构建一个组件,该组件从按周分组的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
};
});
然而,这并没有解决问题,我仍然遇到同样的问题。我做错了什么?
答案 0 :(得分:2)
经过几个小时的调查后,我设法找到了问题的根本原因。显然正在发生的事情是setState()
迟迟未更新week
州。使用较旧版本的州调用API。
为了解决这个问题,我使用了async/await
:
await
代码现在看起来像这样:
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
);
};
这里的主要课程有两个:
setState()
是一个异步函数。大喔。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>