news 2026/7/7 1:56:49

06-高级模式与实战项目——07. Factory模式 - 动态组件创建

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
06-高级模式与实战项目——07. Factory模式 - 动态组件创建

07. Factory模式 - 动态组件创建

概述

Factory 模式是一种根据条件动态创建和返回不同组件的设计模式。它允许在运行时根据配置、类型或状态决定渲染哪个组件,提高代码的灵活性和可维护性。

维度内容
What根据条件动态创建和返回不同组件的模式
Why根据配置或状态动态渲染不同组件
When根据类型渲染不同 UI、动态表单
Where组件工厂函数、动态渲染
Who需要条件渲染的开发者
How`const Component = componentMap[type]

1. 什么是 Factory 模式

1.1 基本概念

Factory 模式使用一个工厂函数或对象映射来动态决定创建哪个组件。

// 基础工厂模式 function getComponent(type) { const components = { text: TextComponent, image: ImageComponent, video: VideoComponent, }; const Component = components[type] || DefaultComponent; return <Component />; } // 使用 function DynamicContent({ type }) { return getComponent(type); }

1.2 为什么需要 Factory 模式

// ❌ 传统方式:大量的条件判断 function Message({ type, data }) { if (type === 'success') { return <SuccessMessage data={data} />; } else if (type === 'error') { return <ErrorMessage data={data} />; } else if (type === 'warning') { return <WarningMessage data={data} />; } else if (type === 'info') { return <InfoMessage data={data} />; } else { return <DefaultMessage data={data} />; } } // ✅ Factory 模式:使用映射 const messageComponents = { success: SuccessMessage, error: ErrorMessage, warning: WarningMessage, info: InfoMessage, }; function Message({ type, data }) { const Component = messageComponents[type] || DefaultMessage; return <Component data={data} />; }

2. 基础实现

2.1 组件映射

// 定义组件映射 const cardComponents = { user: UserCard, product: ProductCard, post: PostCard, comment: CommentCard, }; // 工厂组件 function Card({ type, data }) { const Component = cardComponents[type]; if (!Component) { return <div>未知的卡片类型: {type}</div>; } return <Component data={data} />; } // 使用 function Dashboard() { const items = [ { type: 'user', data: { name: '张三', email: 'zhang@example.com' } }, { type: 'product', data: { name: '手机', price: 5999 } }, { type: 'post', data: { title: 'React 19', content: '...' } }, ]; return ( <div> {items.map((item, index) => ( <Card key={index} type={item.type} data={item.data} /> ))} </div> ); }

2.2 带默认组件

const buttonVariants = { primary: PrimaryButton, secondary: SecondaryButton, danger: DangerButton, success: SuccessButton, }; function Button({ variant, children, ...props }) { const Component = buttonVariants[variant] || DefaultButton; return <Component {...props}>{children}</Component>; } // 使用 <Button variant="primary">主要按钮</Button> <Button variant="danger">危险按钮</Button> <Button variant="custom">默认按钮</Button>

3. 高级实现

3.1 动态组件注册

// 组件注册表 class ComponentRegistry { constructor() { this.components = new Map(); } register(name, component) { this.components.set(name, component); } get(name) { return this.components.get(name); } has(name) { return this.components.has(name); } } const registry = new ComponentRegistry(); // 注册组件 registry.register('text', TextWidget); registry.register('image', ImageWidget); registry.register('chart', ChartWidget); // 工厂组件 function Widget({ type, props }) { const Component = registry.get(type); if (!Component) { return <div>未知组件类型: {type}</div>; } return <Component {...props} />; }

3.2 懒加载工厂

// 懒加载组件映射 const lazyComponents = { dashboard: () => import('./Dashboard'), profile: () => import('./Profile'), settings: () => import('./Settings'), }; function LazyPage({ name }) { const [Component, setComponent] = useState(null); useEffect(() => { const loader = lazyComponents[name]; if (loader) { loader().then(module => setComponent(() => module.default)); } }, [name]); if (!Component) return <div>加载中...</div>; return <Component />; } // 或使用 React.lazy const pageComponents = { dashboard: lazy(() => import('./Dashboard')), profile: lazy(() => import('./Profile')), settings: lazy(() => import('./Settings')), }; function Page({ name }) { const Component = pageComponents[name]; if (!Component) return <div>页面不存在</div>; return ( <Suspense fallback={<div>加载中...</div>}> <Component /> </Suspense> ); }

3.3 带参数的工厂

// 工厂函数返回带配置的组件 function createField(type, config = {}) { const fieldComponents = { text: (props) => <Input type="text" {...config} {...props} />, email: (props) => <Input type="email" {...config} {...props} />, select: (props) => <Select options={config.options} {...props} />, checkbox: (props) => <Checkbox {...config} {...props} />, date: (props) => <DatePicker {...config} {...props} />, }; return fieldComponents[type] || fieldComponents.text; } // 使用 function DynamicForm({ fields }) { return ( <form> {fields.map(field => { const FieldComponent = createField(field.type, field.config); return <FieldComponent key={field.name} name={field.name} />; })} </form> ); } // 配置 const formConfig = [ { name: 'username', type: 'text', config: { placeholder: '用户名' } }, { name: 'email', type: 'email', config: { placeholder: '邮箱' } }, { name: 'role', type: 'select', config: { options: ['admin', 'user'] } }, ];

4. 实际应用场景

4.1 动态表单

// 字段类型映射 const fieldTypes = { text: ({ label, value, onChange }) => ( <div> <label>{label}</label> <input type="text" value={value} onChange={onChange} /> </div> ), number: ({ label, value, onChange }) => ( <div> <label>{label}</label> <input type="number" value={value} onChange={onChange} /> </div> ), select: ({ label, value, onChange, options }) => ( <div> <label>{label}</label> <select value={value} onChange={onChange}> {options.map(opt => ( <option key={opt.value} value={opt.value}>{opt.label}</option> ))} </select> </div> ), checkbox: ({ label, checked, onChange }) => ( <div> <label> <input type="checkbox" checked={checked} onChange={onChange} /> {label} </label> </div> ), textarea: ({ label, value, onChange }) => ( <div> <label>{label}</label> <textarea value={value} onChange={onChange} rows={4} /> </div> ), }; function DynamicField({ field, value, onChange }) { const FieldComponent = fieldTypes[field.type]; if (!FieldComponent) { return <div>未知字段类型: {field.type}</div>; } return ( <FieldComponent label={field.label} value={value} checked={value} onChange={(e) => onChange(field.name, e.target.value)} options={field.options} /> ); } function DynamicForm({ schema, onSubmit }) { const [formData, setFormData] = useState({}); const handleChange = (name, value) => { setFormData(prev => ({ ...prev, [name]: value })); }; const handleSubmit = (e) => { e.preventDefault(); onSubmit(formData); }; return ( <form onSubmit={handleSubmit}> {schema.fields.map(field => ( <DynamicField key={field.name} field={field} value={formData[field.name]} onChange={handleChange} /> ))} <button type="submit">提交</button> </form> ); } // 使用 const formSchema = { fields: [ { name: 'name', type: 'text', label: '姓名' }, { name: 'age', type: 'number', label: '年龄' }, { name: 'gender', type: 'select', label: '性别', options: [ { value: 'male', label: '男' }, { value: 'female', label: '女' }, ]}, { name: 'agree', type: 'checkbox', label: '同意条款' }, { name: 'bio', type: 'textarea', label: '个人简介' }, ], }; <DynamicForm schema={formSchema} onSubmit={(data) => console.log(data)} />

4.2 动态图表

const chartComponents = { line: LineChart, bar: BarChart, pie: PieChart, scatter: ScatterChart, area: AreaChart, }; function Chart({ type, data, options }) { const ChartComponent = chartComponents[type]; if (!ChartComponent) { return <div>不支持的图表类型: {type}</div>; } return <ChartComponent data={data} options={options} />; } // 使用 const charts = [ { type: 'line', data: lineData }, { type: 'bar', data: barData }, { type: 'pie', data: pieData }, ]; function Dashboard() { return ( <div className="dashboard"> {charts.map((chart, i) => ( <Chart key={i} type={chart.type} data={chart.data} /> ))} </div> ); }

4.3 动态通知

const notificationComponents = { success: ({ message, onClose }) => ( <div className="notification success"> <span>✅ {message}</span> <button onClick={onClose}>×</button> </div> ), error: ({ message, onClose }) => ( <div className="notification error"> <span>❌ {message}</span> <button onClick={onClose}>×</button> </div> ), warning: ({ message, onClose }) => ( <div className="notification warning"> <span>⚠️ {message}</span> <button onClick={onClose}>×</button> </div> ), info: ({ message, onClose }) => ( <div className="notification info"> <span>ℹ️ {message}</span> <button onClick={onClose}>×</button> </div> ), }; function Notification({ type, message, onClose }) { const Component = notificationComponents[type] || notificationComponents.info; return <Component message={message} onClose={onClose} />; }

5. 完整示例:CMS 页面构建器

// 组件库 const componentLibrary = { hero: ({ title, subtitle, image }) => ( <div className="hero"> <img src={image} alt={title} /> <h1>{title}</h1> <p>{subtitle}</p> </div> ), features: ({ items }) => ( <div className="features"> {items.map((item, i) => ( <div key={i} className="feature"> <h3>{item.title}</h3> <p>{item.description}</p> </div> ))} </div> ), testimonial: ({ quote, author, role }) => ( <div className="testimonial"> <p>"{quote}"</p> <div className="author"> <strong>{author}</strong> <span>{role}</span> </div> </div> ), pricing: ({ plans }) => ( <div className="pricing"> {plans.map(plan => ( <div key={plan.name} className="plan"> <h3>{plan.name}</h3> <div className="price">¥{plan.price}</div> <ul> {plan.features.map(feature => ( <li key={feature}>{feature}</li> ))} </ul> </div> ))} </div> ), cta: ({ title, buttonText, buttonLink }) => ( <div className="cta"> <h2>{title}</h2> <a href={buttonLink} className="button">{buttonText}</a> </div> ), }; // 页面组件 function PageBuilder({ sections }) { return ( <div className="page-builder"> {sections.map((section, index) => { const Component = componentLibrary[section.type]; if (!Component) { return <div key={index}>未知组件类型: {section.type}</div>; } return <Component key={index} {...section.props} />; })} </div> ); } // 页面配置 const pageConfig = { sections: [ { type: 'hero', props: { title: '欢迎来到我们的网站', subtitle: '最好的产品和服务', image: '/hero.jpg', }, }, { type: 'features', props: { items: [ { title: '功能1', description: '描述1' }, { title: '功能2', description: '描述2' }, { title: '功能3', description: '描述3' }, ], }, }, { type: 'testimonial', props: { quote: '非常棒的产品!', author: '张三', role: 'CEO', }, }, { type: 'pricing', props: { plans: [ { name: '基础版', price: 99, features: ['功能1', '功能2'] }, { name: '专业版', price: 199, features: ['功能1', '功能2', '功能3'] }, ], }, }, { type: 'cta', props: { title: '开始使用', buttonText: '立即购买', buttonLink: '/pricing', }, }, ], }; // 使用 function HomePage() { return <PageBuilder sections={pageConfig.sections} />; }

6. 总结

核心要点

要点说明
核心价值动态选择组件,避免条件判断
实现方式对象映射、工厂函数、注册表
适用场景动态表单、CMS、多类型组件
优势可扩展、易维护

记忆口诀

工厂模式动态选,映射对象最方便
类型配置决定 UI,扩展新类不用愁


7. 相关资源

  • 工厂模式
  • React 动态组件

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 1:51:38

表驱动状态机EFSM

在嵌入式开发中,很多Bug并不是算法导致的,而是状态管理混乱造成的。 设备上电、自检、初始化、运行、异常、升级、休眠……随着产品越来越复杂,各种if...else、switch...case不断叠加,最终代码变成了"意大利面条",维护成本越来越高。 这时候,有限状态机几乎是…

作者头像 李华
网站建设 2026/7/7 1:45:10

储能沙盘模型BMS功能模拟控制系统设计与实现:电压监测、均衡管理与故障保护的STM32方案

摘要 电池管理系统&#xff08;BMS&#xff09;是储能系统的核心控制单元&#xff0c;负责电芯电压监测、温度监测、均衡管理及故障保护等关键功能。在储能沙盘模型中&#xff0c;BMS功能的可视化模拟是区别“外观模型”与“教学演示模型”的分水岭。 本文结合筑城世纪模型在储…

作者头像 李华
网站建设 2026/7/7 1:44:12

字节三面:Skill和Rules为啥要分开设计?我说:因为一个管AI始终可信,一个管AI某时专业,混一起两头都做不好。他说我懂得还挺专业…

Skill和Rules看似都是"给AI下指令"&#xff0c;但本质上解决的是完全不同层次的问题。一个管的是"AI始终要保持的状态"&#xff0c;另一个管的是"AI在特定场景下的专业能力"。混在一起&#xff0c;两头都做不好。 今天就把这件事说清楚。 大模…

作者头像 李华
网站建设 2026/7/7 1:42:45

1200kV冲击发生器现场布置与级数选择

1200kV/120kJ雷电冲击电压发生器用于220kV至500kV电压等级电力设备的雷电冲击耐压试验&#xff0c;产生1.2/50μs标准雷电冲击全波&#xff0c;也可配置截波装置产生截波。设备典型结构为12级100kV或6级200kV两种方案。第一次见到1200kV冲击发生器的时候&#xff0c;第一反应是…

作者头像 李华
网站建设 2026/7/7 1:40:26

Agentic RAG 把检索当成一个工具,和传统 RAG 到底差在哪?

从「固定单跳管道」到「Agent 自主决定检不检、检什么、要不要再检」 面向要落地检索问答的工程师 面试里问「你做过 RAG 吗」&#xff0c;很多人张口就是「切块、向量化、检索 Top-K、塞进提示、让模型答」。这套流程没错&#xff0c;但只是最基础的一版。追问一句「用户问的…

作者头像 李华