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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 08:05:28