React中如何创建子元素为组件的复合组件
React 点调用嵌套组件实现方案
你要实现的是React生态里非常常用的**复合组件(Compound Component)**设计模式,实现逻辑非常简单,不需要引入第三方依赖,核心是利用React组件本质是函数/对象,可以挂载静态属性的特性实现。
核心实现步骤
- 先拆分实现各个独立的子模块组件,比如示例里的
Title、Body,这些子组件和普通React组件没有任何区别,完全支持传入className、绑定事件、嵌套任意JSX内容。 - 实现外层父容器组件,负责整体的布局、共享状态逻辑。如果需要固定子模块的展示位置(比如不管用户怎么传顺序,Title永远在Body上方),可以用React内置的
React.Children、React.isValidElement工具方法遍历传入的children,匹配对应子组件放到指定布局位;如果允许用户自由调整子模块顺序,直接渲染children即可。 - 把子组件挂载为父组件的静态属性,导出时只需要导出父组件,用户调用时直接通过
父组件.子组件的写法就能拿到对应子组件,不需要单独导入子模块。
可直接运行的代码示例
import React from 'react'; // 子组件:标题区,和普通组件写法完全一致 const Title = ({ children, className = '', ...restProps }) => { return ( <h2 className={`my-component-default-title-class ${className}`} {...restProps} // 透传所有传入的props,支持绑定事件、自定义属性等 > {children} </h2> ); }; // 子组件:内容区,支持传入任意JSX const Body = ({ children, className = '', ...restProps }) => { return ( <div className={`my-component-default-body-class ${className}`} {...restProps} > {children} </div> ); }; // 父容器组件 const MyComponent = ({ children, className = '', ...restProps }) => { // 下面这段是固定子组件位置的逻辑,不需要固定位置可以删掉,直接渲染children let titleContent = null; let bodyContent = null; React.Children.forEach(children, (child) => { // 过滤掉null、文本节点等非合法React元素,避免报错 if (!React.isValidElement(child)) return; if (child.type === Title) titleContent = child; if (child.type === Body) bodyContent = child; }); return ( <div className={`my-component-default-wrapper-class ${className}`} {...restProps} > {/* 固定位置写法 */} {titleContent} {bodyContent} {/* 自由顺序写法直接替换为 {children} 即可 */} </div> ); }; // 挂载静态属性,实现点调用语法 MyComponent.Title = Title; MyComponent.Body = Body; export default MyComponent;
扩展说明
- 如果父子组件需要共享隐式状态(比如折叠面板的展开/收起状态、标签页的激活项状态,不需要用户手动透传props),可以配合React Context API实现,父组件在顶层提供Context,子组件通过
useContext直接获取共享状态和方法,这也是复杂复合组件的通用实现方案。 - 这个模式是React官方推荐的关联组件设计方案,主流组件库的Card、Modal、Tabs、Collapse等多区块组件,都是基于这个模式实现的,查阅相关资料直接搜索「React 复合组件」即可找到完整的最佳实践说明。
内容的提问来源于stack exchange,提问作者Beulah Akindele
相关产品推荐
相关产品推荐

