Next.js并行路由共享依赖路由参数的上下文实现方案咨询
Next.js并行路由共享依赖路由参数的上下文实现方案咨询
你好呀!看了你的需求,想在Next.js的两个并行路由(@aside和@main)之间共享一个依赖路由参数userId的上下文,还不想用Redux这类全局状态管理工具,这完全可以实现,不用发愁~
当前文件夹结构
app/ ├── @aside/ │ └── users/ │ └── [userId]/ │ └── todos/ │ └── new/ ├── @main/ │ └── users/ │ └── [userId]/ │ └── todos/ │ └── new/ └── layout.tsx
当前代码示例
layout.tsx
interface LayoutProps { aside: React.ReactNode; main: React.ReactNode; } export default function Layout({ aside, main }: LayoutProps) { return ( <div> {aside} {main} </div> ); }
TodoFormContext.tsx
import React from 'react'; import { UseFormReturn } from 'react-hook-form'; type TodoFormValue = { title: string; description?: string; }; type ContextValue = { form: UseFormReturn<TodoFormValue>; }; const TodoFormContext = React.createContext<ContextValue | null>(null); export const TodoFormProvider = ({ children, userId }: { children: React.ReactNode; userId: string }) => { const form = useForm<TodoFormValue>(); return ( <TodoFormContext.Provider value={{ form }}> {children} </TodoFormContext.Provider> ); }; export const useTodoFormContext = () => { const context = React.useContext(TodoFormContext); if (!context) { throw new Error('useTodoFormContext must be used within a TodoFormProvider'); } return context; };
实现方案:调整路由结构+父Layout提供上下文
目前你的并行路由放在app/根目录下,但userId参数嵌套在并行路由内部,导致根layout.tsx无法获取到参数。我们可以调整路由结构,让并行路由共享同一个包含userId的父路由层级,这样就能在父Layout中获取参数并提供上下文了。
步骤1:调整文件夹结构
把并行路由移到users/[userId]/todos/new层级下,让它们共享同一个带userId的父路由:
app/ └── users/ └── [userId]/ ├── layout.tsx // 上下文提供者的父Layout └── todos/ └── new/ ├── @aside/ │ └── page.tsx ├── @main/ │ └── page.tsx └── layout.tsx // 渲染并行路由的Layout
步骤2:在users/[userId]/layout.tsx中提供上下文
这个Layout可以通过useParams获取到userId,然后将上下文提供者包裹所有子路由内容:
import { useParams } from 'next/navigation'; import { TodoFormProvider } from '@/app/TodoFormContext'; export default function UserIdLayout({ children }: { children: React.ReactNode }) { const { userId } = useParams<{ userId: string }>(); if (!userId) { return <div>User not found</div>; } return ( <TodoFormProvider userId={userId}> {children} </TodoFormProvider> ); }
步骤3:更新todos/new/layout.tsx渲染并行路由
这个Layout负责渲染两个并行路由的内容,和你原来的根Layout逻辑类似:
interface NewTodoLayoutProps { aside: React.ReactNode; main: React.ReactNode; } export default function NewTodoLayout({ aside, main }: NewTodoLayoutProps) { return ( <div className="flex"> <div className="w-1/3">{aside}</div> <div className="w-2/3">{main}</div> </div> ); }
步骤4:在并行路由组件中使用上下文
现在@aside/page.tsx和@main/page.tsx都能通过自定义钩子访问共享的上下文了:
// app/users/[userId]/todos/new/@aside/page.tsx import { useTodoFormContext } from '@/app/TodoFormContext'; export default function AsideTodoForm() { const { form } = useTodoFormContext(); return ( <div> <input {...form.register('title')} placeholder="Todo Title" /> </div> ); }
// app/users/[userId]/todos/new/@main/page.tsx import { useTodoFormContext } from '@/app/TodoFormContext'; export default function MainTodoForm() { const { form } = useTodoFormContext(); return ( <div> <textarea {...form.register('description')} placeholder="Todo Description" /> <button type="submit" onClick={form.handleSubmit((data) => console.log(data))}> Submit Todo </button> </div> ); }
方案优势
- 利用Next.js路由的层级嵌套特性,
users/[userId]/layout.tsx会包裹所有子路由(包括并行路由),确保上下文能被所有需要的组件访问。 - 完全依赖React内置的Context API,不需要引入额外的全局状态管理库,轻量且符合Next.js的路由设计逻辑。
备注:内容来源于stack exchange,提问作者TheAschr
相关产品推荐
相关产品推荐

