为何能用useState在异步请求中管理加载状态?
异步事件处理中useState状态更新的困惑
我观察到有人在async/await函数中使用useState处理fetch请求时的加载状态。如下代码中,点击提交后loggingIn会被设为true,login函数执行完成后又被设为false,可据此展示加载spinner。
const [logginIn, setLogginIn] = useState(false); async function handleSubmit(e: React.FormEvent<HTMLFormElement>) { e.preventDefault(); try { setLogginIn(true); await login(email, password); } catch (error) { if (error instanceof Error) { setLoginError(error.message); } } finally { setLogginIn(false); } }
但根据React文档:
即使事件处理代码是异步的,渲染过程中状态变量的值也不会改变
我原以为两次setLogginIn会被一起执行。是因为React适配async/await分别调度两次状态更新?但我又认为状态仅随重渲染改变,事件处理函数应仅触发一次重渲染,对此我感到困惑。
解答
核心原因在于await会打断事件处理函数的同步执行流程,让React的状态更新批处理机制无法把两次setLogginIn合并。
React在同步的事件处理函数里会自动批处理状态更新——也就是把多个setState调用合并成一次重渲染,提升性能。但一旦遇到await,函数会暂停执行,此时当前的同步执行上下文结束,React会立即处理之前的setLogginIn(true),触发第一次重渲染,把加载状态设为true。
等login(email, password)这个异步操作完成后,函数才会继续执行到finally块里的setLogginIn(false),这时候是在一个新的异步上下文里,React会再次调度状态更新,触发第二次重渲染,把加载状态关掉。
所以你看到的两次状态更新会分别触发重渲染,刚好能实现加载spinner的显示和隐藏,这是完全符合React的运行逻辑的。
内容的提问来源于stack exchange,提问作者Wesley Jessie
相关产品推荐
相关产品推荐

