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

Next.js中如何在服务器组件内的两个客户端组件间共享数据?

跨客户端组件共享状态的解决方案

针对你在服务器组件中拆分两个客户端组件(日期选择器、计分板)且需要同步状态的问题,以下是几种实用方案:

1. 状态提升到共同的父客户端组件

服务器组件无法使用React状态钩子,你可以在服务器组件内部嵌套一个客户端组件作为父容器,把共享状态放在这个父组件中,再通过props传递给两个子组件,同时在父组件里按需求布局两个子组件的位置。

示例代码:

// app/DateScoreContainer.tsx(客户端组件)
'use client';

import { useState } from 'react';
import DatePicker from './DatePicker';
import Scoreboard from './Scoreboard';

export default function DateScoreContainer() {
  const [selectedDate, setSelectedDate] = useState(new Date());

  return (
    <>
      {/* 把日期选择器放在头部区域 */}
      <header className="page-header">
        <DatePicker onDateChange={setSelectedDate} />
      </header>
      {/* 把计分板放在主内容区域 */}
      <main className="page-main">
        <Scoreboard currentDate={selectedDate} />
      </main>
    </>
  );
}

// app/page.tsx(服务器组件)
import DateScoreContainer from './DateScoreContainer';

export default function Home() {
  return <DateScoreContainer />;
}

2. 使用React Context API

如果两个组件的层级较深、props传递路径繁琐,可以用Context实现全局状态共享,避免逐层传参的麻烦。

示例代码:

// app/DateContext.tsx
'use client';

import { createContext, useContext, useState, ReactNode } from 'react';

type DateContextType = {
  selectedDate: Date;
  setSelectedDate: (date: Date) => void;
};

const DateContext = createContext<DateContextType | undefined>(undefined);

export function DateProvider({ children }: { children: ReactNode }) {
  const [selectedDate, setSelectedDate] = useState(new Date());
  return (
    <DateContext.Provider value={{ selectedDate, setSelectedDate }}>
      {children}
    </DateContext.Provider>
  );
}

export function useDate() {
  const context = useContext(DateContext);
  if (!context) {
    throw new Error('useDate必须在DateProvider内部使用');
  }
  return context;
}

// app/DatePicker.tsx(客户端组件)
'use client';

import { useDate } from './DateContext';

export default function DatePicker() {
  const { setSelectedDate } = useDate();

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.value) setSelectedDate(new Date(e.target.value));
  };

  return <input type="date" onChange={handleChange} />;
}

// app/Scoreboard.tsx(客户端组件)
'use client';

import { useDate } from './DateContext';

// 模拟根据日期获取分数的函数
const getScoresByDate = (date: Date) => [
  { id: 1, value: 85 },
  { id: 2, value: 92 },
];

export default function Scoreboard() {
  const { selectedDate } = useDate();
  const scores = getScoresByDate(selectedDate);

  return (
    <div className="scoreboard">
      <h3>{selectedDate.toLocaleDateString()} 的分数</h3>
      <ul>
        {scores.map(score => <li key={score.id}>科目分数:{score.value}</li>)}
      </ul>
    </div>
  );
}

// app/page.tsx(服务器组件)
import { DateProvider } from './DateContext';
import DatePicker from './DatePicker';
import Scoreboard from './Scoreboard';

export default function Home() {
  return (
    <DateProvider>
      <header><DatePicker /></header>
      <main><Scoreboard /></main>
    </DateProvider>
  );
}

3. 使用轻量状态管理库

如果项目中有多处跨组件共享状态的需求,或者需要处理更复杂的状态逻辑,Zustand、Jotai这类轻量库是更高效的选择,无需复杂配置即可实现全局状态共享。

以Zustand为例:

// app/dateStore.ts
'use client';

import { create } from 'zustand';

type DateStore = {
  selectedDate: Date;
  setSelectedDate: (date: Date) => void;
};

export const useDateStore = create<DateStore>((set) => ({
  selectedDate: new Date(),
  setSelectedDate: (date) => set({ selectedDate: date }),
}));

// app/DatePicker.tsx
'use client';

import { useDateStore } from './dateStore';

export default function DatePicker() {
  const setSelectedDate = useDateStore(state => state.setSelectedDate);

  return <input type="date" onChange={(e) => e.target.value && setSelectedDate(new Date(e.target.value))} />;
}

// app/Scoreboard.tsx
'use client';

import { useDateStore } from './dateStore';

export default function Scoreboard() {
  const selectedDate = useDateStore(state => state.selectedDate);
  const scores = getScoresByDate(selectedDate);

  return (
    <div className="scoreboard">
      <h3>{selectedDate.toLocaleDateString()} 的分数</h3>
      {/* 渲染分数列表 */}
    </div>
  );
}

// app/page.tsx(服务器组件)
import DatePicker from './DatePicker';
import Scoreboard from './Scoreboard';

export default function Home() {
  return (
    <div>
      <header><DatePicker /></header>
      <main><Scoreboard /></main>
    </div>
  );
}

方案选择建议

  • 仅两个简单组件共享状态:优先选状态提升,无额外依赖,逻辑最直观;
  • 组件层级深、传参繁琐:选择Context API;
  • 多组件共享状态或需复杂状态逻辑:用轻量状态管理库更高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 02:33:37