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

Next.js中如何将getServerSideProps数据更新到React Context状态

方案1:页面内初始化(适合单页面使用场景、需要跨页面保活状态场景)

getServerSideProps返回的属性在页面组件首次渲染时必然已就绪,你遇到的tasksData为undefined的问题,大概率是依赖项缺失或未做存在判断导致,修正写法如下:

// pages/index.tsx
import { useBoard } from '../contexts/board'
import { TaskAction } from '../constants/task'

const Home = ({ tasksData }: { tasksData: Task[] }) => {
  const { tasks, dispatch } = useBoard()

  useEffect(() => {
    // 仅在数据存在、且Context未初始化时派发更新
    if (tasksData && tasks.length === 0) {
      dispatch({ 
        type: TaskAction.SET_TASKS, 
        payload: tasksData 
      })
    }
    // 显式声明依赖项,dispatch引用稳定不会触发重复执行
  }, [tasksData, tasks, dispatch])

  // 后续所有逻辑均从Context取tasks作为唯一数据源
  return (
    <div>
      {tasks.map(task => <TaskCard key={task.id} task={task} />)}
    </div>
  )
}

export const getServerSideProps = async () => {
  const tasksData = await fetch('/api/tasks').then(res => res.json())
  return { props: { tasksData } }
}

如果需要避免首次渲染空状态,可以加加载态判断:if (tasks.length === 0) return <Loading />。


方案2:全局Context传参(适合多页面共享初始数据场景,无性能损耗)

不需要给_app.tsx加getInitialProps,_app默认可以拿到所有页面的pageProps,直接透传为Context初始值即可,完全保留Next.js所有优化特性:

  1. 首先修改Context Provider的定义,支持传入初始值:
// contexts/board.tsx
import { useReducer, createContext, useContext } from 'react'
import { TaskAction } from '../constants/task'

type BoardState = {
  tasks: Task[]
  // 其他状态字段
}

const boardReducer = (state: BoardState, action: any) => {
  switch (action.type) {
    case TaskAction.SET_TASKS:
      return { ...state, tasks: action.payload }
    // 其他action逻辑
    default: return state
  }
}

const BoardContext = createContext<{
  state: BoardState
  dispatch: React.Dispatch<any>
} | null>(null)

export const BoardProvider = ({ 
  children, 
  initialTasks = [] 
}: { 
  children: React.ReactNode 
  initialTasks?: Task[] 
}) => {
  const [state, dispatch] = useReducer(boardReducer, {
    tasks: initialTasks,
    // 其他初始状态
  })

  return (
    <BoardContext.Provider value={{ state, dispatch }}>
      {children}
    </BoardContext.Provider>
  )
}

export const useBoard = () => useContext(BoardContext)!
  1. 修改_app.tsx,将页面属性透传给Provider:
// _app.tsx
import type { AppProps } from 'next/app'
import { BoardProvider } from '../contexts/board'

export default function App({ Component, pageProps }: AppProps) {
  return (
    <BoardProvider initialTasks={pageProps.tasksData ?? []}>
      <Component {...pageProps} />
    </BoardProvider>
  )
}
  1. 页面组件直接从Context取数据即可,不需要额外useEffect:
// pages/index.tsx
import { useBoard } from '../contexts/board'

const Home = () => {
  const { state: { tasks } } = useBoard()
  return <Board tasks={tasks} />
}

export const getServerSideProps = async () => {
  const tasksData = await fetch('/api/tasks').then(res => res.json())
  return { props: { tasksData } }
}

注意事项

  • 如果需要跨页面切换时保留Context的状态(比如编辑到一半的任务草稿),优先使用方案1,方案2在页面切换时会用新页面的pageProps重置Context初始值。
  • 如果部分页面不需要加载任务数据,pageProps.tasksData会自动回退为空数组,不影响正常运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 21:45:03