React异步函数setState批处理问题求助(Next.js场景)
解决Next.js客户端组件表单提交时Loading状态不显示的问题
核心问题:React在异步函数中会对setState调用进行批处理。你代码中await前的两次状态更新(禁用按钮、设置Loading文本)会被合并处理,而await后的状态更新会立即触发渲染,导致Loading状态还没来得及展示就被覆盖,看起来像是直接跳过了步骤1。
解决方案
方法1:使用flushSync强制同步更新
导入React的flushSync工具,将await前的状态更新包裹起来,强制React立即执行状态更新并渲染UI,而非批处理:
import { flushSync } from 'react'; async function Execute(data: FormData) { flushSync(() => { SetInteractable(false); setMessage("Loading"); }); const response = await SendGiftAction(data); SetInteractable(true); setMessage(response.Success ? "" : response.Error); }
方法2:利用微任务延迟Server Action调用
通过await Promise.resolve()让状态更新的渲染先完成,再执行Server Action,本质是利用JavaScript微任务队列的执行顺序:
async function Execute(data: FormData) { SetInteractable(false); setMessage("Loading"); // 等待状态更新完成渲染 await Promise.resolve(); const response = await SendGiftAction(data); SetInteractable(true); setMessage(response.Success ? "" : response.Error); }
修改后的完整组件代码
"use client"; import { SendGiftAction } from "@/app/actions/SendGiftAction"; import { useState, flushSync } from "react"; export default function GoldGiftForm() { const [interactable, setInteractable] = useState(true); const [message, setMessage] = useState(""); async function Execute(data: FormData) { flushSync(() => { setInteractable(false); setMessage("Loading"); }); const response = await SendGiftAction(data); setInteractable(true); setMessage(response.Success ? "" : response.Error); } return ( <form action={Execute}> <h3>Send Gold Gift</h3> <input name="userID" type="text" placeholder="User ID" /> <input name="gold" type="number" placeholder="Gold" /> <button type="submit" disabled={!interactable}> Send Gift </button> <p>{message}</p> </form> ); }
内容的提问来源于stack exchange,提问作者Moe Baker
相关产品推荐
相关产品推荐

