06-高级模式与实战项目——07. Factory模式 - 动态组件创建 07. Factory模式 - 动态组件创建概述Factory 模式是一种根据条件动态创建和返回不同组件的设计模式。它允许在运行时根据配置、类型或状态决定渲染哪个组件提高代码的灵活性和可维护性。维度内容What根据条件动态创建和返回不同组件的模式Why根据配置或状态动态渲染不同组件When根据类型渲染不同 UI、动态表单Where组件工厂函数、动态渲染Who需要条件渲染的开发者Howconst 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: zhangexample.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 variantprimary主要按钮/Button Button variantdanger危险按钮/Button Button variantcustom默认按钮/Button3. 高级实现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 typetext {...config} {...props} /, email: (props) Input typeemail {...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 typetext value{value} onChange{onChange} / /div ), number: ({ label, value, onChange }) ( div label{label}/label input typenumber 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 typecheckbox 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 typesubmit提交/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 classNamedashboard {charts.map((chart, i) ( Chart key{i} type{chart.type} data{chart.data} / ))} /div ); }4.3 动态通知const notificationComponents { success: ({ message, onClose }) ( div classNamenotification success span✅ {message}/span button onClick{onClose}×/button /div ), error: ({ message, onClose }) ( div classNamenotification error span❌ {message}/span button onClick{onClose}×/button /div ), warning: ({ message, onClose }) ( div classNamenotification warning span⚠️ {message}/span button onClick{onClose}×/button /div ), info: ({ message, onClose }) ( div classNamenotification 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 classNamehero img src{image} alt{title} / h1{title}/h1 p{subtitle}/p /div ), features: ({ items }) ( div classNamefeatures {items.map((item, i) ( div key{i} classNamefeature h3{item.title}/h3 p{item.description}/p /div ))} /div ), testimonial: ({ quote, author, role }) ( div classNametestimonial p{quote}/p div classNameauthor strong{author}/strong span{role}/span /div /div ), pricing: ({ plans }) ( div classNamepricing {plans.map(plan ( div key{plan.name} classNameplan h3{plan.name}/h3 div classNameprice¥{plan.price}/div ul {plan.features.map(feature ( li key{feature}{feature}/li ))} /ul /div ))} /div ), cta: ({ title, buttonText, buttonLink }) ( div classNamecta h2{title}/h2 a href{buttonLink} classNamebutton{buttonText}/a /div ), }; // 页面组件 function PageBuilder({ sections }) { return ( div classNamepage-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 动态组件