在 useState 环境中模拟 setState 的第二个参数.让 setState 发生后发生一些事情



在以前的 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 中推导出实际需要发生的操作。

在基于钩子的函数组件中,我将如何执行上述操作?


更好的用例是具有两个按钮的屏幕,一个用于加载上一个按钮,另一个用于加载下一个按钮。当状态为 true 时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>
}
}

问题"是飞行中的异步操作"是"这些异步操作中的任何一个在飞行中"的简化,因此您可以单独对每个异步操作进行建模,然后计算isLoading。像这样的自定义钩子可能会起作用:

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
...
}

相关内容

  • 没有找到相关文章

最新更新