首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

狗教我React—— 5 种组件提取思路与实践

  • 25-04-24 21:01
  • 3814
  • 12379
juejin.cn

在开发时,经常遇到一些高度重复但略有差异的 UI 模式,此时我们当然会把组件提取出去,但是组件提取的方式有很多,怎么根据不同场景选取合适的方式呢?尤其时在复杂的业务场景中,组件提取的思路影响着着代码的可维护性、可读性以及扩展性。本文将以一个[详情]组件为例,探讨 5 种不同的 React 组件提取思路,分析它们的适用场景与实现技巧。

image.png

一、直接实现

tsx
代码解读
复制代码
// 全部写在一个组件中 const ProductDetail = ({ productItem }) => ( <div className="prose"> <section> <h2>小标题1h2> <p>{productItem.content}p> section> {/* 重复类似结构 */} div> );

问题分析:

  • 重复代码量随区块增加线性增长
  • 修改样式需要全局搜索替换
  • 难以应对需求变化(如新增内容区块)

这种实现方式虽然简单,但当内容结构复杂或者频繁变化时,会导致代码的重复度过高,难以维护。

二、进化之路:5 种组件提取模式

模式 1:配置驱动式(Config-Driven)

又名数据驱动模式、JSON Schema 模式

核心思想 ​​:将 UI 结构抽象为数据配置,实现 UI = f(config)

tsx
代码解读
复制代码
const ProductContent = ({ sections }) => ( <div className="prose"> {sections.map((section) => ( <section key={section.title}> <h2>{section.title}h2> {renderContent(section)} section> ))} div> );

优势:

  • 动态生成能力:可以通过修改配置文件快速调整页面内容。
  • 可维护:所有配置集中管理,易于维护。
  • 内容与结构解耦:内容与展示结构分离,修改时可不关注结构,只通过修改配置文件实现。

劣势:

  • 配置文件需要严格规范。
  • 调试困难,配置文错误时难以定位问题。

适用场景:

  • 内容管理系统(CMS)
  • 动态内容渲染
  • 适合简单页面,配置文件结构清晰,且内容变化频繁的场景。

模式 2:独立导出式(Explicit Export)

又名模块化模式

​ 核心思想 ​​:将组件拆分为独立单元,然后在主组件中组合使用。

tsx
代码解读
复制代码
// 分别导出组件 export const ProductContent = ({ children }) => <div className="prose">{children}div>; export const ProductSection = ({ title, content }) => ( <section> <h2>{title}h2> <p>{content}p> section> ); // 使用 import { ProductContent, ProductSection } from './components';

优势:

  • 组件独立性更强,可以更容易进行单元测试。
  • 支持 Tree Shaking,有助于减少最终打包体积。

Tree Shaking:通过 ESM 静态分析移除未使用代码的优化手段。详情可参考这篇文章:

  • 类型定义更简单,易于理解。

适用场景:

这种模式适合代码结构较为松散,或者需要精细化的性能优化(如 Tree Shaking)的场景。

补充:代码优化技巧

tsx
代码解读
复制代码
// 使用 index.ts 统一导出 // components/index.ts export * from './ProductContent'; export * from './ProductSection'; // 使用时统一导入 import { ProductContent, ProductSection } from '@/components';

模式 3:对象属性式(Namespace Pattern)

也叫命名空间、复合组件

核心思想 ​​:通过对象属性建立组件关系,实现组件的嵌套与组合。

tsx
代码解读
复制代码
// 主组件容器 const ProductContent = ({ children }) => <div className="prose">{children}div>; // 添加子组件属性 ProductContent.Section = ({ title, content }) => ( <section> <h2>{title}h2> <p>{content}p> section> ); // 使用 <ProductContent> <ProductContent.Section title="小标题" content={data} /> ProductContent>;

优势:

  • 结构层级清晰,便于集中管理,易于理解。
  • 子组件可以继承容器样式(如.prose排版体系)

风险:

  • 子组件与容器组件耦合度较高,修改时需要关注容器组件的变化。

适用场景:

  • 子组件与容器组件关系紧密,中等复杂度场景(3-5 个管理子组件)。

补充:使用 TypeScript 合并类型声明

tsx
代码解读
复制代码
interface ProductContentType extends React.FC { Section: React.FC<SectionProps>; } const ProductContent = () => { /*...*/ } as ProductContentType; ProductContent.Section = Section;

模式 4:上下文共享式(Context Provider)

核心思想:通过 Context 实现跨层级状态共享,避免 PropsDrilling

最佳实践:

  • 使用 createContext 创建上下文
  • 使用 useContext 获取上下文数据
  • 使用 Provider 组件包裹子组件,实现数据共享
tsx
代码解读
复制代码
const ProductContext = createContext({ theme: 'light' }); // 默认值 const ProductProvider = ({ children }) => ( <ProductContext.Provider value={{ theme: 'dark' }}> <div className="prose">{children}div> ProductContext.Provider> ); const Section = ({ title }) => { const { theme } = useContext(ProductContext); return /* 根据 theme 渲染 */; };

补充:像这样的用法很常见,比如在封装自定义的 Form 时,通过 ​​Context 集中管理表单状态与校验逻辑 ​​,实现表单组件的 ​​ 跨层级数据共享 ​​、​​ 逻辑复用与交互行为的统一控制 ​​,避免 Props 逐层透传。

注意 ​​:频繁更新的 Context 可能导致子组件不必要的渲染,建议结合 useMemo 或状态管理库优化。

关于 useMemo 的使用,可以参考这篇文章:狗教我React——组件渲染性能优化关键词: shouldComponentUpdate、PureComnent、Rea - 掘金_

适用场景:

  • 需要在多个组件中共享状态,特别是在较大规模的应用中,Context 可以避免过度的 props 传递。
  • 适合主题切换、语言切换等全局性功能。

模式 5:高阶组件式(HOC)

tsx
代码解读
复制代码
const withProductStyle = (Component) => { return (props) => ( <div className="case-wrapper"> <Component {...props} /> div> ); }; const EnhancedSection = withProductStyle(Section);

高阶组件(HOC)是一种函数,它接受一个组件作为参数,并返回一个新的组件。

适用于逻辑复用、跨组件扩展等场景,特别是在需要增强现有组件的功能时。

比如在封装埋点监控时,可以通过高阶组件模式实现组件的自动埋点,无需在多个组件中重复编写埋点逻辑。

tsx
代码解读
复制代码
const withTrack = (Component) => { return (props) => { const handleClick = (event) => { console.log('按钮被点击了,记录埋点:', props.label); // 模拟埋点 }; return <Component {...props} onClick={handleClick} />; }; }; // 使用高阶组件增强 Button 组件 const TrackedButton = withTracking(Button);

三、模式对比与选型推荐

模式维护成本复用层级类型支持适用场景
配置驱动式中页面级复杂动态内容
独立导出式低组件级简单组件库
对象属性式中模块级中等强关联组件,标准业务模块
上下文共享式高应用级复杂全局状态共享
高阶组件式高功能级中等埋点监控

四、小结

组件抽象的本质是在复用性与灵活性之间寻找平衡点。在抽离组件时,需要根据项目的需求,逐步引入适合的模式,避免一开始就过度设计。同时,可以利用 TypeScript 的类型推导来增强类型安全。另外就是要保持性能意识,避免不必要的渲染和性能瓶颈。

在实际项目中,往往需要根据业务特点组合使用多种模式,才能达到最佳效果。希望这些模式能为您的组件化开发提供新的思路。

注:本文转载自juejin.cn的本狗超级忙的的文章"https://juejin.cn/post/7495955310965243923"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

104
前端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top