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

Next.js中如何将组件作为Props传递给ModuleToggle子组件?

React/Next.js 组件复用问题:封装三分段切换组件并传递子组件Props

我是React和Next.js新手,需要把三分段切换逻辑抽成独立子组件ModuleToggle,核心需求:

  • 将不同页面的Full、Condensed、Video组件作为Props传递给子组件
  • 数十个页面都需要这个三分段切换器,但每个页面的这三个组件实现不同

初始可运行代码(career_progression.tsx)

export default function CareerProgression() {
   // "SegmentedControl" 是一个三分段切换器,根据选中项加载不同组件
   const [section, setSection] = useState<'video' | 'condensed' | 'full'>('full');

   const renderComponent:any = () => {
      switch(section) {
         case 'video':
            return <Video />
         case 'condensed':
            return <Condensed />
         case 'full':
            return <Full />
      }
   }

   return (
      <>
         { renderComponent() } {/* 根据用户切换更新页面内容 */}
         {/* 使用预构建的Mantine组件 */}
         <SegmentedControl
            value={section}
            onChange={(value: 'video' | 'condensed' | 'full') => setSection(value)}
            data={[
               { label: 'Video', value: 'video'}, 
               { label: 'Condensed Detail', value: 'condensed'}, 
               { label: 'Full Detail', value: 'full'}, 
            ]}
         />
      </>
   );
}

export function Full() {
   return ( <p>Full</p> );
}

export function Condensed() {
   return ( <p>Condensed</p> );
}

export function Video() {
   return ( <p>Video</p> );
}

改造后的父组件(new career_progression.tsx)

export default function CareerProgression() {
   // 声明要传递给子组件的状态
   const [activeComponent, setActiveComponent] = useState<React.ReactNode>(null);

   return (
      <>
         { activeComponent } {/* 期望由子组件更新并显示的内容 */}
         {/* 尝试创建独立组件 */}
         <ModuleToggle_withState 
            video={<Video/>} 
            condensed={<Condensed/>} 
            full={<Full/>}
            setActiveComponent={setActiveComponent} 
         />
      </>
   );
}

export function Full() {
   return ( <p>Full</p> );
}

export function Condensed() {
   return ( <p>Condensed</p> );
}

export function Video() {
   return ( <p>Video</p> );
}

子组件(ModuleToggle.tsx)

import { Dispatch, useEffect } from 'react';

export function ModuleToggle_withState(Video:Component, Condensed:Component, 
   Full:Component, setActiveComponent:any) {

   // 尝试实现但不确定如何正确引用组件Props
   useEffect(() => {
      switch(section) {
         case 'video':
            setActiveComponent=Video
         case 'condensed':
            setActiveComponent=Condensed
         case 'full':
            setActiveComponent=Full
      }
   }, [section]);

   }
   return (
      <SegmentedControl
         value={section}
         onChange={(value: 'video' | 'condensed' | 'full') => setSection(value)}
         data={[
            { label: 'Video', value: 'video'}, 
            { label: 'Condensed Detail', value: 'condensed'}, 
            { label: 'Full Detail', value: 'full'}, 
         ]}
      />
   );
}

问题修正与完整解决方案

你的复用思路没问题,但在Props接收、状态管理和组件渲染上存在几个关键错误,以下是修正后的实现:

核心修正点

  1. React组件的Props是一个对象,必须通过解构或props.xxx访问,不能直接作为独立参数接收
  2. 子组件需自行维护切换状态,或通过回调同步给父组件
  3. 组件传递可选择「已渲染JSX」或「组件类型」两种方式,按需选择

修正后的子组件:ModuleToggle.tsx

import { useState } from 'react';
import { SegmentedControl } from '@mantine/core';

// 定义Props类型,明确接收的组件和回调
type ModuleToggleProps = {
  videoComponent: React.ReactNode;
  condensedComponent: React.ReactNode;
  fullComponent: React.ReactNode;
  // 可选:父组件需要监听切换状态时使用
  onSectionChange?: (section: 'video' | 'condensed' | 'full') => void;
};

export function ModuleToggle({
  videoComponent,
  condensedComponent,
  fullComponent,
  onSectionChange,
}: ModuleToggleProps) {
  // 子组件内部维护切换状态
  const [section, setSection] = useState<'video' | 'condensed' | 'full'>('full');

  const handleChange = (value: 'video' | 'condensed' | 'full') => {
    setSection(value);
    // 通知父组件切换状态(可选)
    onSectionChange?.(value);
  };

  // 根据当前选中项返回对应组件
  const getActiveComponent = () => {
    switch (section) {
      case 'video':
        return videoComponent;
      case 'condensed':
        return condensedComponent;
      case 'full':
        return fullComponent;
      default:
        return null;
    }
  };

  return (
    <>
      {/* 直接在子组件内渲染激活的组件 */}
      {getActiveComponent()}
      <SegmentedControl
        value={section}
        onChange={handleChange}
        data={[
          { label: 'Video', value: 'video' },
          { label: 'Condensed Detail', value: 'condensed' },
          { label: 'Full Detail', value: 'full' },
        ]}
      />
    </>
  );
}

修正后的父组件:career_progression.tsx

import { ModuleToggle } from './ModuleToggle';

export default function CareerProgression() {
  // 如果不需要在父组件中获取切换状态,可省略此state
  // const [activeSection, setActiveSection] = useState<'video' | 'condensed' | 'full'>('full');

  return (
    <ModuleToggle
      // 传递已渲染的JSX(简单场景)
      videoComponent={<Video />}
      condensedComponent={<Condensed />}
      fullComponent={<Full />}
      // 可选:监听切换状态
      // onSectionChange={(section) => setActiveSection(section)}
    />
  );
}

export function Full() {
  return <p>Full</p>;
}

export function Condensed() {
  return <p>Condensed</p>;
}

export function Video() {
  return <p>Video</p>;
}

进阶方案:传递组件类型(支持动态传Props)

如果需要在子组件中给传递的组件添加额外Props,可直接传递组件类型而非已渲染的JSX:

子组件修改部分

type ModuleToggleProps = {
  Video: React.ComponentType;
  Condensed: React.ComponentType;
  Full: React.ComponentType;
};

export function ModuleToggle({ Video, Condensed, Full }: ModuleToggleProps) {
  // ...状态逻辑不变
  const getActiveComponent = () => {
    switch (section) {
      case 'video':
        return <Video someProp="自定义值" />; // 动态传递Props
      case 'condensed':
        return <Condensed />;
      case 'full':
        return <Full />;
      default:
        return null;
    }
  };
}

父组件调用修改

<ModuleToggle
  Video={Video}
  Condensed={Condensed}
  Full={Full}
/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 12:13:53