【发布时间】:2020-05-14 20:16:12
【问题描述】:
在之前的 react 版本中,我们可以在状态改变后执行代码,方法是:
setState( prevState => {myval: !prevState.myval}, () => {
console.log("myval is changed now");
)
并确保第二个“位”仅使用更新的代码执行。现在,其中一个示例描述了可以使用React.useEffect 实现“类似”的东西:
const [myval, setMyval] = React.useState(false);
React.useEffect(() => {
console.log("myval is changed now");
}
//somewhere
setMyval(o => !o);
虽然这看起来不错,但在我的情况下并没有帮助:在我的情况下,“需要发生什么效果”取决于状态发生变化的位置,最初:
//somewhere
setState( prevState => {myval: !prevState.myval}, () => {
console.log("myval is changed now");
)
//somewhere else
setState( prevState => {myval: !prevState.myval}, () => {
console.log("myval has changed somewhere else");
)
将这些更改为useState + setMyval 会在两个位置触发相同的效果,因此我们无法在 useEffect 中推导出实际需要发生的操作。
如何在基于钩子的函数组件中执行上述操作?
一个更好的用例是一个有两个按钮的屏幕,一个用于加载上一个,另一个用于加载下一个。当isLoading 状态为真时按钮被禁用并且仅在加载时执行操作。为了确保只发生一次加载,我们不能只是“采取行动”,就好像状态立即发生变化:状态变化是异步的,因此可能会发生竞争条件。
在改变状态时使用回调可以防止这种竞争条件,并确保只发生一次加载:
class SomScreen extends React.component {
state = { isLoading: false }
render() {
<div>
<button
disabled={this.state.isLoading}
onclick={(e) => {
if (!this.state.isLoading) {
this.setState((p) => ({isLoading: true}), () => {
await fetchPreviousDataAndDoSomethingWithIt()
setState({isLoading: false});
});
}
}
/>Previous</button>
<button
disabled={this.state.isLoading}
onclick={(e) => {
if (!this.state.isLoading) {
this.setState((p) => ({isLoading: true}), () => {
await fetchNextDataAndDoSomethingWithIt()
setState({isLoading: false});
});
}
}
/>Next</button>
</div>
}
}
【问题讨论】:
标签: reactjs state react-hooks