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所有优化特性:
- 首先修改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)!
- 修改
_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> ) }
- 页面组件直接从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
相关产品推荐
相关产品推荐

