Next.js 13中如何在Server Action后调用Toast通知
Next.js 13 Server Action 完成数据变更后触发客户端 Toast 方案
Server Action 运行在服务端,无法直接调用客户端的 Hook/Context,核心思路是通过服务端返回的操作结果,在客户端组件中触发 Toast,以下是几种实用实现方式:
方案一:直接调用 Server Action 并处理返回结果
在客户端组件中调用 Server Action,根据返回的成功/失败状态触发 Toast:
1. 定义 Server Action
// app/actions.ts 'use server'; export async function updateData(formData: FormData) { try { // 执行数据变更逻辑(比如数据库操作) // await db.item.update({ ... }); return { success: true, message: '数据更新成功' }; } catch (error) { return { success: false, message: '数据更新失败:' + (error as Error).message }; } }
2. 客户端组件调用并触发 Toast
// app/components/UpdateForm.tsx 'use client'; import { updateData } from '../actions'; import { useToast } from '../context/ToastContext'; export default function UpdateForm() { const { showToast } = useToast(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget as HTMLFormElement); const result = await updateData(formData); // 根据返回结果触发 Toast showToast({ type: result.success ? 'success' : 'error', content: result.message }); }; return ( <form onSubmit={handleSubmit}> <input type="text" name="content" placeholder="输入内容" /> <button type="submit">提交更新</button> </form> ); }
方案二:使用 useFormState 监听提交状态
利用 React 的 useFormState 绑定 Server Action,通过状态变化自动触发 Toast:
// app/components/UpdateForm.tsx 'use client'; import { useFormState, useFormStatus } from 'react-dom'; import { updateData } from '../actions'; import { useToast } from '../context/ToastContext'; import { useEffect } from 'react'; // 初始化提交状态 const initialState = { success: false, message: '' }; export default function UpdateForm() { const { showToast } = useToast(); const [submitState, formAction] = useFormState(updateData, initialState); // 监听提交状态变化,触发 Toast useEffect(() => { if (submitState.message) { showToast({ type: submitState.success ? 'success' : 'error', content: submitState.message }); } }, [submitState, showToast]); // 可选:获取提交中状态,禁用按钮 const { pending } = useFormStatus(); return ( <form action={formAction}> <input type="text" name="content" placeholder="输入内容" /> <button type="submit" disabled={pending}> {pending ? '提交中...' : '提交更新'} </button> </form> ); }
方案三:服务器组件中触发的处理方式
如果需要在服务器组件中触发操作,需将交互逻辑封装到客户端子组件中:
1. 服务器页面
// app/page.tsx import UpdateButton from './components/UpdateButton'; export default function HomePage() { return ( <div> <h1>数据管理页面</h1> {/* 服务器组件无法直接处理交互,使用客户端组件封装 */} <UpdateButton /> </div> ); }
2. 客户端按钮组件
// app/components/UpdateButton.tsx 'use client'; import { updateData } from '../actions'; import { useToast } from '../context/ToastContext'; export default function UpdateButton() { const { showToast } = useToast(); const handleClick = async () => { const result = await updateData(new FormData()); showToast({ type: result.success ? 'success' : 'error', content: result.message }); }; return <button onClick={handleClick}>执行数据更新</button>; }
关键注意事项
- 所有调用 Toast Hook/Context 的组件必须添加
'use client'指令,确保运行在客户端。 - Server Action 仅负责服务端逻辑,不要在其中包含任何客户端相关代码(如 Hook 调用)。
- 如果使用第三方 Toast 库(如 react-hot-toast),逻辑完全通用,只需替换
showToast为对应库的调用方法即可。
内容的提问来源于stack exchange,提问作者Re-Angelo
相关产品推荐
相关产品推荐

