Next.js中如何在page.tsx与layout.tsx间传递参数?
Next.js App Router中Page与Layout的状态共享方案
针对你提到的场景——页面按钮控制Layout中MUI步进器高亮,同时支持后续双向传参,下面提供两种实用方案:
方案一:React Context(推荐用于复杂交互与扩展)
通过React Context实现跨组件状态共享,适合需要双向传参、复杂状态管理的场景,后续扩展成本低。
1. 创建步骤状态上下文
在app/stepContext.tsx中定义共享的状态与方法:
'use client'; import { createContext, useContext, useState, ReactNode } from 'react'; type StepContextType = { currentStep: number; setCurrentStep: (step: number) => void; // 后续需要Layout向Page传参时,直接添加对应状态/方法即可 // 示例:layoutSharedData: string; updateLayoutData: (data: string) => void; }; const StepContext = createContext<StepContextType | undefined>(undefined); export function StepProvider({ children }: { children: ReactNode }) { const [currentStep, setCurrentStep] = useState(0); // 可选:根据路由自动同步步骤(避免刷新后状态丢失) // const pathname = usePathname(); // useEffect(() => { // const routeStepMap = { '/step1': 0, '/step2': 1, '/step3': 2 }; // setCurrentStep(routeStepMap[pathname as keyof typeof routeStepMap] ?? 0); // }, [pathname]); return ( <StepContext.Provider value={{ currentStep, setCurrentStep }}> {children} </StepContext.Provider> ); } export function useStepContext() { const context = useContext(StepContext); if (!context) { throw new Error('useStepContext必须在StepProvider范围内使用'); } return context; }
2. 在Layout中嵌入步进器并关联状态
修改app/layout.tsx,添加客户端组件标识,包裹上下文并渲染MUI步进器:
'use client'; import { StepProvider, useStepContext } from './stepContext'; import { Stepper, Step, StepLabel } from '@mui/material'; export default function RootLayout({ children }: { children: ReactNode }) { const { currentStep } = useStepContext(); const steps = ['步骤1', '步骤2', '步骤3']; // 与路由对应的步骤列表 return ( <html lang="zh-CN"> <body> <StepProvider> <Stepper activeStep={currentStep} alternativeLabel> {steps.map((label) => ( <Step key={label}> <StepLabel>{label}</StepLabel> </Step> ))} </Stepper> {children} </StepProvider> </body> </html> ); }
3. 在Page中触发步骤更新
以app/step1/page.tsx为例,页面按钮调用上下文方法更新步进器并跳转路由:
'use client'; import { useStepContext } from '../../stepContext'; import { useRouter } from 'next/navigation'; import { Button } from '@mui/material'; export default function Step1Page() { const { setCurrentStep } = useStepContext(); const router = useRouter(); const handleNext = () => { setCurrentStep(prev => prev + 1); // 更新步进器状态 router.push('/step2'); // 跳转到对应路由 }; return ( <div> <h1>步骤1页面</h1> <Button variant="contained" onClick={handleNext}>下一步</Button> </div> ); }
方案二:URL搜索参数(轻量同步,适合简单场景)
如果仅需单向同步步进器状态,且希望刷新页面后状态不丢失,可通过URL参数实现:
1. Layout中读取URL参数控制步进器
'use client'; import { useSearchParams } from 'next/navigation'; import { Stepper, Step, StepLabel } from '@mui/material'; export default function RootLayout({ children }: { children: ReactNode }) { const searchParams = useSearchParams(); const currentStep = parseInt(searchParams.get('step') || '0', 10); const steps = ['步骤1', '步骤2', '步骤3']; return ( <html lang="zh-CN"> <body> <Stepper activeStep={currentStep} alternativeLabel> {steps.map((label) => ( <Step key={label}> <StepLabel>{label}</StepLabel> </Step> ))} </Stepper> {children} </body> </html> ); }
2. Page中跳转时携带参数
'use client'; import { useRouter } from 'next/navigation'; import { Button } from '@mui/material'; export default function Step1Page() { const router = useRouter(); const handleNext = () => { router.push('/step2?step=1'); // 携带步骤参数跳转 }; return ( <div> <h1>步骤1页面</h1> <Button variant="contained" onClick={handleNext}>下一步</Button> </div> ); }
后续扩展:Layout向Page传参
如果需要从Layout向Page传递数据,直接在Context中新增字段即可:
- 在
StepContextType中添加需要共享的状态与更新方法; - 在
StepProvider中初始化对应状态; - Layout中调用更新方法修改数据,Page中通过
useStepContext()读取即可。
内容的提问来源于stack exchange,提问作者Slippy
相关产品推荐
相关产品推荐

