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

Next.js 13基于文件夹路由中,如何从layout.js向page.js传递props?

解决方案:Next.js 13 布局向子页面传递状态

核心问题原因

在Next.js 13 App Router中,children并非单个React元素,而是React节点数组(或流式渲染内容),直接用React.cloneElement处理会失效——因为它只能操作单个元素。

正确实现方式

方法1:使用React Context(适配文件夹路由结构)

这是最贴合App Router设计的方案,无需组件导入或全局状态管理,仅在当前路由组内生效:

  1. 在(DropDownPages)目录下创建Context文件
// app/(DropDownPages)/MenuContext.js
"use client";
import { createContext, useContext, useState } from "react";

const MenuContext = createContext();

export function MenuProvider({ children }) {
  const [selectedMenu, setSelectedMenu] = useState(null);

  const handleTitleClick = (menu) => {
    setSelectedMenu(menu);
  };

  return (
    <MenuContext.Provider value={{ selectedMenu, handleTitleClick }}>
      {children}
    </MenuContext.Provider>
  );
}

export function useMenu() {
  const context = useContext(MenuContext);
  if (!context) {
    throw new Error("useMenu必须在MenuProvider范围内使用");
  }
  return context;
}
  1. 修改父布局app/(DropDownPages)/layout.js
    将状态逻辑移到Provider中,布局仅负责渲染UI:
"use client"
import styled from "styled-components";
import { MenuProvider, useMenu } from "./MenuContext";

const 전체 = 'all'
const 상품 = 'product'
const 카테고리 = 'category'
const 기획전 = 'exhibition'
const 브랜드 = 'brand'

// 省略styled-components样式代码

function CategoryLayout({ children }) {
  const { handleTitleClick } = useMenu();

  return (
    <Section>
      <nav className="flex justify-center items-center mt-6 mb-6">
        <MenuBox onClick={() => handleTitleClick(전체)} >
          <ImageWrapper><StyledImage src="/전체.png" /></ImageWrapper>
          <Title>전체</Title>
        </MenuBox>
        <MenuBox onClick={() => handleTitleClick(상품)} >
          <ImageWrapper><StyledImage src="/상품.png" /></ImageWrapper>
          <Title>전체</Title>
        </MenuBox>
        <MenuBox onClick={() => handleTitleClick(카테고리)} >
          <ImageWrapper><StyledImage src="/카테고리.png" /></ImageWrapper>
          <Title>전체</Title>
        </MenuBox>
        <MenuBox onClick={() => handleTitleClick(기획전)} >
          <ImageWrapper><StyledImage src="/기획전.png" /></ImageWrapper>
          <Title>전체</Title>
        </MenuBox>
        <MenuBox onClick={() => handleTitleClick(브랜드)} >
          <ImageWrapper><StyledImage src="/브랜드.png" /></ImageWrapper>
          <Title>전체</Title>
        </MenuBox>
      </nav>
      <Main>{children}</Main>    
    </Section>
  )
}

export default function Category({ children }) {
  return (
    <MenuProvider>
      <CategoryLayout>{children}</CategoryLayout>
    </MenuProvider>
  );
}
  1. 子页面接收状态(如product/page.js)
"use client";
import styled from "styled-components";
import { useMenu } from "../MenuContext";

export default function Product() {       
  const { selectedMenu } = useMenu();
  console.log(selectedMenu); // 现在能正常获取选中菜单值

  // 省略其他代码
}

方法2:遍历子元素批量传递Props

如果不想用Context,可通过React.Children.map逐个处理子元素,但注意该方案仅适用于静态子元素场景,对流式渲染兼容性较差:

修改app/(DropDownPages)/layout.js的渲染部分:

// 省略其他代码
<Main>
  {Children.map(children, child => 
    cloneElement(child, { selectedMenu })
  )}
</Main>    

子页面即可直接通过props接收selectedMenu:

export default function Product({selectedMenu}) {       
  console.log(selectedMenu); // 正常输出选中值
}

方案对比

  • Context方案:适配App Router流式渲染特性,支持复杂页面结构,是官方推荐的路由组内传值方式。
  • Children.map方案:实现简单,但局限性大,仅适合静态子组件场景。

内容的提问来源于stack exchange,提问作者Lee Doyu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:14:58