在 React 中,除了高阶组件(HOC)和 Render Props,还有多种实现代码复用的方法,下面为你介绍几种常见的方式及其适用场景:
1. 自定义 Hooks(Custom Hooks)
自定义 Hooks 是 React 16.8 引入 Hooks 后推荐的代码复用方式,它允许你将有状态的逻辑提取到可复用的函数中。
示例代码
import { useState, useEffect } from 'react';
// 自定义 Hook,用于处理表单输入
const useInput = (initialValue = '') => {
const [value, setValue] = useState(initialValue);
const onChange = (e) => {
setValue(e.target.value);
};
return {
value,
onChange,
setValue
};
};
// 使用自定义 Hook 的组件
const Form = () => {
const username = useInput('');
const password = useInput('');
const handleSubmit = (e) => {
e.preventDefault();
console.log('提交表单:', {
username: username.value,
password: password.value
});
};
return (
<form onSubmit={handleSubmit}>
<input type="text" {...username} placeholder="用户名" />
<input type="password" {...password} placeholder="密码" />
<button type="submit">登录</button>
</form>
);
};
优点
- 简洁高效:相比高阶组件和 Render Props,自定义 Hooks 不会增加组件层级,代码结构更清晰。
- 状态逻辑复用:可以将复杂的状态管理逻辑封装在 Hook 中,方便多个组件复用。
- 类型安全:在 TypeScript 中使用自定义 Hooks 更加类型安全。
适用场景
- 复用状态逻辑,如表单处理、数据获取、动画状态等。
- 共享副作用操作,如订阅、定时器等。
2. 组合组件(Component Composition)
通过将小的、单一职责的组件组合成更大的组件来实现代码复用。
示例代码
// 基础组件
const Button = ({ children, onClick, className }) => (
<button onClick={onClick} className={className}>
{children}
</button>
);
const Input = ({ value, onChange, placeholder }) => (
<input value={value} onChange={onChange} placeholder={placeholder} />
);
// 组合组件
const FormField = ({ label, value, onChange, placeholder }) => (
<div className="form-field">
<label>{label}</label>
<Input value={value} onChange={onChange} placeholder={placeholder} />
</div>
);
// 使用组合组件
const UserForm = () => {
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
return (
<form>
<FormField
label="用户名"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="请输入用户名"
/>
<FormField
label="邮箱"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="请输入邮箱"
/>
<Button className="submit-button">提交</Button>
</form>
);
};
优点
- 直观易懂:组件职责明确,组合方式简单直接。
- 灵活可定制:可以根据需要组合不同的组件,实现多样化的功能。
适用场景
- 复用 UI 元素,如按钮、输入框、卡片等。
- 构建复杂组件时,将功能拆分为多个小的、可复用的组件。
3. 上下文 API(Context API)
使用 React 的上下文 API 可以在组件树中共享状态,避免通过多层组件传递 props。
示例代码
// 创建上下文
const UserContext = React.createContext();
// 提供者组件
const UserProvider = ({ children }) => {
const [user, setUser] = useState(null);
const login = (username) => {
setUser({ username });
};
const logout = () => {
setUser(null);
};
return (
<UserContext.Provider value={
{ user, login, logout }}>
{children}
</UserContext.Provider>
);
};
// 使用上下文的组件
const Profile = () => {
const { user } = useContext(UserContext);
return (
<div>
{user ? (
<p>欢迎,{user.username}</p>
) : (
<p>请先登录</p>
)}
</div>
);
};
// 在应用中使用
const App = () => {
return (
<UserProvider>
<div>
<Profile />
{/* 其他组件 */}
</div>
</UserProvider>
);
};
优点
- 跨层级共享状态:避免了“props 层层传递”的问题,使代码更简洁。
- 全局状态管理:适合在整个应用或部分组件树中共享状态。
适用场景
- 共享全局状态,如用户信息、主题设置等。
- 减少多层级组件之间的 props 传递。
4. 函数组件 + Props
这是最基本的代码复用方式,通过将组件的行为和数据通过 props 传递来实现复用。
示例代码
// 可复用的列表组件
const List = ({ items, renderItem }) => (
<ul>
{items.map((item, index) => (
<li key={index}>{renderItem(item)}</li>
))}
</ul>
);
// 使用列表组件
const App = () => {
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' }
];
return (
<div>
<List
items={users}
renderItem={(user) => <span>{user.name}</span>}
/>
</div>
);
};
优点
- 简单直接:不需要额外的概念,容易理解和使用。
- 灵活定制:通过 props 可以灵活控制组件的行为和渲染方式。
适用场景
- 复用简单的 UI 组件,如列表、卡片等。
- 组件的行为和数据可以通过 props 简单传递的场景。
5. 状态管理库(Redux/MobX)
使用状态管理库可以将应用的状态集中管理,实现状态逻辑的复用。
示例代码(Redux)
// 定义 action
const increment = () => ({ type: 'INCREMENT' });
const decrement = () => ({ type: 'DECREMENT' });
// 定义 reducer
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
};
// 创建 store
const store = createStore(counterReducer);
// 使用 connect 连接组件
const Counter = ({ count, increment, decrement }) => (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
const mapStateToProps = (state) => ({
count: state
});
const mapDispatchToProps = {
increment,
decrement
};
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
优点
- 集中管理状态:使状态管理更加可预测和易于调试。
- 跨组件共享状态:多个组件可以共享相同的状态和状态更新逻辑。
适用场景
- 复杂应用的状态管理。
- 需要在多个不相关组件之间共享状态的场景。
总结
在 React 中实现代码复用的方法有很多种,每种方法都有其适用场景:
- 自定义 Hooks:适合复用状态逻辑和副作用操作。
- 组件组合:适合复用 UI 元素和构建复杂组件。
- 上下文 API:适合跨层级共享状态。
- 函数组件 + Props:适合简单组件的复用。
- 状态管理库:适合复杂应用的状态管理和跨组件状态共享。
在实际开发中,可以根据具体需求选择合适的代码复用方式,也可以将多种方式结合使用,以达到最佳的代码复用效果。