在 React 中,组合组件(Component Composition)和高阶组件(Higher-Order Component,HOC)是构建复杂应用的两种核心模式。它们各有优势,通常结合使用以实现代码复用、逻辑抽象和可维护性。以下是如何结合这两种模式构建复杂应用的具体方法:
一、组合组件:构建基础 UI 单元
组合组件通过将小的、单一职责的组件组合成更大的组件,是构建复杂应用的基础。
1. 原子组件(Atomic Components)
创建最小的、不可分割的 UI 单元,如按钮、输入框等。
// Button.js
const Button = ({ children, onClick, variant }) => {
return (
<button
onClick={onClick}
className={`btn ${variant === 'primary' ? 'btn-primary' : 'btn-default'}`}
>
{children}
</button>
);
};
// Input.js
const Input = ({ label, value, onChange, type }) => {
return (
<div className="form-group">
<label>{label}</label>
<input type={type} value={value} onChange={onChange} />
</div>
);
};
2. 分子组件(Molecular Components)
将原子组件组合成具有完整功能的组件,如表单、卡片等。
// LoginForm.js
const LoginForm = ({ onSubmit }) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
onSubmit({ username, password });
};
return (
<form onSubmit={handleSubmit}>
<Input
label="用户名"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<Input
label="密码"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<Button variant="primary" type="submit">登录</Button>
</form>
);
};
3. 容器组件(Container Components)
将分子组件组合成页面级组件,处理数据和状态逻辑。
// AuthPage.js
const AuthPage = () => {
const handleLogin = (credentials) => {
// 处理登录逻辑
console.log('登录:', credentials);
};
return (
<div className="auth-page">
<h1>用户登录</h1>
<LoginForm onSubmit={handleLogin} />
</div>
);
};
二、高阶组件:复用跨组件逻辑
高阶组件用于抽象和复用跨组件的公共逻辑,如状态管理、权限控制等。
1. 状态管理 HOC
复用状态逻辑,如表单验证、数据获取等。
// withFormState.js
const withFormState = (WrappedComponent) => {
return (props) => {
const [formData, setFormData] = useState({});
const [errors, setErrors] = useState({});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = (callback) => (e) => {
e.preventDefault();
// 验证逻辑...
callback(formData);
};
return (
<WrappedComponent
{...props}
formData={formData}
errors={errors}
handleChange={handleChange}
handleSubmit={handleSubmit}
/>
);
};
};
// 使用 HOC
const EnhancedLoginForm = withFormState(LoginForm);
2. 权限控制 HOC
控制组件访问权限,如用户认证、角色检查等。
// withAuth.js
const withAuth = (WrappedComponent) => {
return (props) => {
const { user } = useContext(AuthContext);
if (!user) {
return <Redirect to="/login" />;
}
return <WrappedComponent {...props} />;
};
};
// 使用 HOC
const ProtectedDashboard = withAuth(Dashboard);
3. 性能优化 HOC
复用性能优化逻辑,如懒加载、防抖等。
// withDebounce.js
const withDebounce = (WrappedComponent, delay = 300) => {
return (props) => {
const [debouncedValue, setDebouncedValue] = useState(props.value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(props.value);
}, delay);
return () => clearTimeout(timer);
}, [props.value, delay]);
return <WrappedComponent {...props} value={debouncedValue} />;
};
};
三、结合使用:构建复杂应用架构
将组合组件和高阶组件结合,可以构建分层、可扩展的应用架构。
1. 目录结构示例
src/
├── components/ # 组合组件
│ ├── atoms/ # 原子组件(按钮、输入框等)
│ ├── molecules/ # 分子组件(表单、卡片等)
│ ├── organisms/ # 容器组件(页面片段)
│ └── templates/ # 页面模板
├── hocs/ # 高阶组件
│ ├── withAuth.js
│ ├── withFormState.js
│ └── withLoading.js
├── context/ # 上下文
├── hooks/ # 自定义 Hooks
└── pages/ # 页面组件
2. 实际应用示例
// pages/UserDashboard.js
const UserDashboard = () => {
const { user } = useContext(AuthContext);
return (
<div className="dashboard">
<Header user={user} />
<Sidebar />
<MainContent>
<UserProfile user={user} />
<RecentActivity />
</MainContent>
</div>
);
};
// 使用 HOC 增强页面组件
export default withAuth(withLoading(UserDashboard));
四、最佳实践
1. 组合优先,HOC 辅助
- 组合组件:适合构建 UI 层次和复用视觉元素。
- 高阶组件:适合抽象非视觉逻辑(如状态管理、权限控制)。
2. 避免过度使用 HOC
- 过多的 HOC 嵌套会导致组件层级过深,增加调试难度。
使用
compose
函数组合多个 HOC,减少嵌套:const enhance = compose( withAuth, withLoading, withFormState ); export default enhance(UserDashboard);
3. 与自定义 Hooks 结合
将部分 HOC 逻辑迁移到自定义 Hooks 中,减少组件层级:
// useFormState.js
const useFormState = (initialValues) => {
const [formData, setFormData] = useState(initialValues);
const [errors, setErrors] = useState({});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
};
return { formData, errors, handleChange };
};
// 在组件中直接使用 Hook
const LoginForm = () => {
const { formData, handleChange } = useFormState({ username: '', password: '' });
// ...
};
4. 性能优化
- 对高阶组件返回的组件使用
React.memo
避免不必要的渲染。 - 使用
useMemo
和useCallback
缓存昂贵的计算和回调函数。
五、总结
组合组件 | 高阶组件 |
---|---|
构建 UI 层次结构 | 复用非视觉逻辑 |
扁平化组件结构 | 可能增加组件嵌套 |
直接传递 props 和状态 | 通过包装组件注入 props 和状态 |
适合视觉元素复用 | 适合跨组件逻辑复用 |
复杂应用的理想架构:
- 底层:原子组件(组合)
- 中层:分子组件(组合)+ 高阶组件(增强逻辑)
- 顶层:页面组件(组合 + 高阶组件)+ 状态管理(Context/Hooks)
通过合理组合这两种模式,可以构建出高内聚、低耦合、可维护的复杂 React 应用。