在之前的 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 中得出实际需要发生的操作。
在基于钩子(Hook)的函数组件中我该如何做?
<小时/>更好的用例是一个有两个按钮的屏幕,一个用于加载上一个按钮,另一个用于加载下一个按钮。当 isLoading
状态为 true 时,按钮将被禁用,并且仅在加载时执行操作。为了确保只发生单个负载,我们不能只是“行动”就好像状态立即更改一样:状态更改是异步的,因此可能会发生竞争条件。
在更改状态时使用回调可以防止这种竞争情况并确保只发生一次加载:
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>
}
}
最佳答案
问题“是否是正在执行的异步操作”是“是否有任何正在执行的异步操作”的缩减,因此您可以单独对每个异步操作进行建模,然后计算 isLoading
。像这样的自定义 Hook 可能会起作用:
function useAsyncAction(asyncAction) {
const [isLoading, setIsLoading] = useState(false);
const callAsyncAction = useCallback(async () => {
setIsLoading(true);
await asyncAction();
setIsLoading(false);
}, []);
return [
isLoading,
callAsyncAction,
]
}
//
function SomScreen() {
const [asyncAIsLoading, callAsyncA] =
useAsyncAction(fetchPreviousDataAndDoSomethingWithIt);
const [asyncBIsLoading, callAsyncB] =
useAsyncAction(fetchNextDataAndDoSomethingWithIt);
const isLoading = asyncAIsLoading || asyncBIsLoading
...
}
关于reactjs - 在 useState 环境中模拟 setState 的第二个参数。让 setState 发生后发生一些事情,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59965287/