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接收、状态管理和组件渲染上存在几个关键错误,以下是修正后的实现:
核心修正点
- React组件的Props是一个对象,必须通过解构或
props.xxx访问,不能直接作为独立参数接收 - 子组件需自行维护切换状态,或通过回调同步给父组件
- 组件传递可选择「已渲染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
相关产品推荐
相关产品推荐

