You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS 13中服务端与客户端组件的数据交互问题求解

NextJS 13 服务端组件与客户端组件数据交互解决方案

问题根源

你的代码报错是因为服务端组件(Home页面,无'use client'声明的async组件)无法向客户端组件传递非序列化的props,比如函数handleInput。NextJS在服务端渲染时需要将组件props序列化后传给客户端,而函数不支持序列化,因此直接传递会触发错误。

同时,客户端组件不能直接调用服务端的文件操作函数(如saveData),这类服务端逻辑必须通过中间层(API路由或Server Actions)与客户端交互。


方案1:使用API路由(通用方案)

通过创建API路由作为中间层,客户端组件通过HTTP请求触发服务端的数据写入操作。

步骤1:创建保存数据的API路由

在app/api/save/route.js中编写处理POST请求的逻辑:

import { saveData } from '@/app/data';
import { NextResponse } from 'next/server';

export async function POST(request) {
  const requestData = await request.json();
  await saveData(requestData);
  return NextResponse.json({ success: true });
}

步骤2:修改客户端Input组件

移除handleInput props,改为直接调用API路由:

'use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'

export default function Input() {
  const [value, setValue] = useState('')
  const router = useRouter()

  const handleSave = async () => {
    if (!value) return;
    
    await fetch('/api/save', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ someKey: value })
    });

    // 保存后刷新页面,触发服务端组件重新获取最新数据
    router.refresh();
    setValue('');
  }

  return (
    <div>
      <input 
        type="text" 
        value={value} 
        onChange={(e) => setValue(e.target.value)}
      />
      <button onClick={handleSave}>Save</button>
    </div>
  )
}

步骤3:简化Home页面

服务端组件仅负责获取初始数据并渲染组件:

import { SomeComponent } from './components/component'
import { getData } from './data'
import Input from './components/input'

export default async function Home() {
  const data = await getData()

  return (
    <div>
      <SomeComponent data={data} />
      <Input />
    </div>
  )
}

方案2:使用Server Actions(NextJS 13.4+ 推荐方案)

Server Actions是NextJS 13.4+推出的特性,无需编写API路由,可直接在客户端调用服务端函数。

步骤1:定义Server Action

在app/actions.js中声明服务端操作(需添加'use server'指令):

'use server'
import { saveData } from './data';

export async function handleSaveData(data) {
  await saveData(data);
}

步骤2:修改客户端Input组件

导入并调用Server Action:

'use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'
import { handleSaveData } from '../actions'

export default function Input() {
  const [value, setValue] = useState('')
  const router = useRouter()

  const handleSave = async () => {
    if (!value) return;
    
    await handleSaveData({ someKey: value });
    router.refresh(); // 刷新页面获取最新数据
    setValue('');
  }

  return (
    <div>
      <input 
        type="text" 
        value={value} 
        onChange={(e) => setValue(e.target.value)}
      />
      <button onClick={handleSave}>Save</button>
    </div>
  )
}

步骤3:Home页面保持不变

同方案1的Home页面代码,无需额外修改。


核心原则总结

  1. 服务端组件与客户端组件之间仅能传递可序列化的props(字符串、数字、普通对象等),函数、Symbol等非序列化类型禁止传递。
  2. 所有服务端专属逻辑(文件读写、数据库操作等)必须通过API路由或Server Actions暴露给客户端调用,客户端组件不能直接执行服务端代码。

内容的提问来源于stack exchange,提问作者Cirrocumulus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 04:20:27