Next.js 13 App目录:如何将服务器组件函数传递给客户端组件?
可行实现方案
方案1:使用Server Actions(Next.js 13.4+ 推荐)
Server Actions是App Router下官方支持的服务器端函数调用方式,无需将父组件转为客户端组件,直接可将标记为服务器端的函数传递给客户端组件调用。
服务器组件示例(如app/Page.js)
// 服务器组件,无需添加'use client' import ClientButton from './ClientButton'; // 定义Server Action,必须用'use server'标记 async function handleServerLogic() { 'use server'; // 这里编写你的服务器端逻辑:数据库操作、数据处理等 console.log('执行服务器端函数'); return { success: true }; } export default function ServerComponent() { return ( <div> {/* 将Server Action传递给客户端组件 */} <ClientButton action={handleServerLogic} /> {/* 大型资源保持服务器渲染,不会发送到客户端 */} <img src="/large-asset.jpg" alt="大型图片" /> <audio src="/large-audio.mp3" controls /> </div> ); }
客户端组件示例(app/ClientButton.js)
'use client'; export default function ClientButton({ action }) { const handleClick = async () => { // 直接调用Server Action const result = await action(); console.log(result); // 处理服务器返回的结果 }; return <button onClick={handleClick}>执行服务器逻辑</button>; }
如果需要跟踪执行状态,可结合React的useActionState:
'use client'; import { useActionState } from 'react'; export default function ClientButton({ action }) { const [actionState, formAction] = useActionState(action, null); return ( <form action={formAction}> <button type="submit">执行服务器逻辑</button> {actionState?.success && <p>执行成功!</p>} </form> ); }
注意:Next.js 13.4+ 默认开启Server Actions,低版本需在
next.config.js中手动配置experimental.serverActions: true。
方案2:调用API Route
将服务器端逻辑封装为API接口,客户端组件通过fetch调用该接口,完全避免函数传递的问题。
API路由示例(app/api/trigger-action/route.js)
export async function POST(request) { // 执行服务器端逻辑 console.log('执行服务器端函数'); return Response.json({ success: true }); }
客户端组件示例(app/ClientButton.js)
'use client'; export default function ClientButton() { const handleClick = async () => { const res = await fetch('/api/trigger-action', { method: 'POST' }); const data = await res.json(); console.log(data); }; return <button onClick={handleClick}>执行服务器逻辑</button>; }
服务器组件
直接渲染客户端按钮即可,无需传递任何函数,大型资源保持服务器渲染。
方案3:通过状态触发服务器组件重渲染
客户端组件点击后修改URL参数或调用revalidatePath,触发服务器组件重新渲染并执行逻辑,适合需要刷新页面内容的场景。
客户端组件示例(app/ClientButton.js)
'use client'; import { useRouter } from 'next/navigation'; export default function ClientButton() { const router = useRouter(); const handleClick = () => { // 通过URL参数触发服务器逻辑 router.push('/?action=run'); // 或用revalidatePath触发页面重新验证 // revalidatePath('/'); }; return <button onClick={handleClick}>触发服务器逻辑</button>; }
服务器组件示例(app/Page.js)
import { redirect } from 'next/navigation'; import ClientButton from './ClientButton'; export default async function ServerComponent({ searchParams }) { // 检查URL参数,执行服务器逻辑 if (searchParams?.action === 'run') { console.log('执行服务器端函数'); // 执行完重定向,避免刷新重复触发 redirect('/'); } return ( <div> <ClientButton /> <img src="/large-asset.jpg" alt="大型图片" /> <audio src="/large-audio.mp3" controls /> </div> ); }
内容的提问来源于stack exchange,提问作者yonaries
相关产品推荐
相关产品推荐

