您现在的位置是:网站首页 > React中的设计模式实践文章详情
React中的设计模式实践
陈川
【
JavaScript
】
20414人已围观
12849字
React作为现代前端开发的主流框架,其灵活性和组件化思想为设计模式的应用提供了广阔空间。合理运用设计模式能提升代码的可维护性、复用性和扩展性,尤其在复杂应用场景中效果显著。
组件组合模式
组合模式在React中体现为组件树的嵌套结构。通过将小组件组合成更大组件,可以构建复杂的UI层次。典型的例子是表单组件的封装:
const Input = ({ label, ...props }) => (
<div className="form-group">
<label>{label}</label>
<input {...props} />
</div>
);
const Form = ({ children }) => (
<form className="form-container">
{children}
<button type="submit">提交</button>
</form>
);
// 使用组合
<Form>
<Input label="用户名" name="username" />
<Input label="密码" type="password" name="password" />
</Form>
这种模式的优势在于:
- 每个组件只关注单一职责
- 通过props.children实现灵活的内容注入
- 组件之间解耦,便于独立测试和维护
高阶组件模式
高阶组件(HOC)是React中实现横切关注点的经典方式。它接收组件作为参数并返回增强后的新组件:
function withLoading(Component) {
return function EnhancedComponent({ isLoading, ...props }) {
return isLoading ? (
<div className="loader">加载中...</div>
) : (
<Component {...props} />
);
};
}
// 使用HOC增强组件
const EnhancedTable = withLoading(DataTable);
// 渲染时
<EnhancedTable isLoading={true} data={data} />
常见HOC应用场景包括:
- 权限控制
- 数据获取
- 错误边界处理
- 性能监控
渲染属性模式
Render Props通过函数prop共享组件逻辑,比HOC更具灵活性:
class MouseTracker extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
});
};
render() {
return (
<div onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
// 使用渲染属性
<MouseTracker
render={({ x, y }) => (
<h1>
鼠标位置: {x}, {y}
</h1>
)}
/>
这种模式的优点在于:
- 逻辑与UI完全解耦
- 避免HOC的组件嵌套问题
- 动态组合行为更灵活
状态管理中的观察者模式
在全局状态管理中,观察者模式是Redux等库的核心:
// 创建store
const store = createStore(reducer);
// 订阅状态变化
const unsubscribe = store.subscribe(() => {
console.log('状态变更:', store.getState());
});
// 派发action
store.dispatch({ type: 'INCREMENT' });
// React组件连接
const Counter = connect(
state => ({ count: state.count }),
dispatch => ({
increment: () => dispatch({ type: 'INCREMENT' })
})
)(function({ count, increment }) {
return <button onClick={increment}>{count}</button>;
});
观察者模式在React中的关键点:
- 单一数据源原则
- 状态变更通过订阅/通知机制
- 避免直接修改状态
容器/展示组件模式
这种模式将组件分为两类:
- 容器组件:管理状态和逻辑
- 展示组件:负责UI渲染
// 展示组件
const UserList = ({ users, onDelete }) => (
<ul>
{users.map(user => (
<li key={user.id}>
{user.name}
<button onClick={() => onDelete(user.id)}>删除</button>
</li>
))}
</ul>
);
// 容器组件
class UserListContainer extends React.Component {
state = { users: [] };
componentDidMount() {
fetch('/api/users')
.then(res => res.json())
.then(users => this.setState({ users }));
}
handleDelete = (id) => {
this.setState(prev => ({
users: prev.users.filter(user => user.id !== id)
}));
};
render() {
return <UserList
users={this.state.users}
onDelete={this.handleDelete}
/>;
}
}
这种分离带来的好处:
- 业务逻辑与UI解耦
- 展示组件可复用性高
- 测试更简单(展示组件只需快照测试)
工厂模式创建组件
工厂模式可用于动态创建不同类型的组件:
const Button = ({ type, ...props }) => {
const components = {
primary: PrimaryButton,
danger: DangerButton,
default: DefaultButton
};
const Component = components[type] || components.default;
return <Component {...props} />;
};
// 使用工厂
<Button type="primary" onClick={handleClick}>
主要按钮
</Button>
适用场景包括:
- 需要根据配置动态渲染组件
- 统一管理相似组件的创建逻辑
- 简化复杂条件渲染
策略模式处理算法
策略模式允许在运行时选择算法:
const validationStrategies = {
email: value => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
phone: value => /^1[3-9]\d{9}$/.test(value),
required: value => value.trim() !== ''
};
const FormField = ({ type, value, onValidate }) => {
const validate = () => {
const isValid = validationStrategies[type](value);
onValidate(isValid);
};
return (
<div>
<input
type={type}
value={value}
onChange={e => onValidate(validationStrategies[type](e.target.value))}
/>
</div>
);
};
策略模式的优势:
- 避免复杂的条件语句
- 算法可独立变化和扩展
- 便于单元测试
装饰器模式增强功能
虽然React不直接支持装饰器语法,但可以实现类似效果:
function withLogging(WrappedComponent) {
return class extends React.Component {
componentDidMount() {
console.log(`组件 ${WrappedComponent.name} 已挂载`);
}
render() {
return <WrappedComponent {...this.props} />;
}
};
}
// 使用装饰器
@withLogging
class MyComponent extends React.Component {
render() {
return <div>装饰器示例</div>;
}
}
装饰器常用于:
- 日志记录
- 性能监测
- 异常捕获
- 权限校验
依赖注入模式
通过Context API实现依赖注入:
const ServicesContext = React.createContext();
const ApiService = {
fetchData: () => Promise.resolve([1, 2, 3])
};
const App = () => (
<ServicesContext.Provider value={ApiService}>
<DataConsumer />
</ServicesContext.Provider>
);
const DataConsumer = () => {
const { fetchData } = useContext(ServicesContext);
const [data, setData] = useState([]);
useEffect(() => {
fetchData().then(setData);
}, [fetchData]);
return <div>{data.join(', ')}</div>;
};
依赖注入的好处:
- 降低组件间的直接依赖
- 便于模拟服务进行测试
- 运行时动态替换实现
备忘录模式实现撤销
备忘录模式可用于实现状态历史记录:
function useUndo(initialState) {
const [history, setHistory] = useState([initialState]);
const [index, setIndex] = useState(0);
const current = history[index];
const setState = (newState) => {
const newHistory = history.slice(0, index + 1);
setHistory([...newHistory, newState]);
setIndex(newHistory.length);
};
const undo = () => index > 0 && setIndex(index - 1);
const redo = () => index < history.length - 1 && setIndex(index + 1);
return [current, setState, { undo, redo, canUndo: index > 0, canRedo: index < history.length - 1 }];
}
// 使用示例
const [text, setText, { undo, redo }] = useUndo('');
享元模式优化性能
享元模式通过共享相似对象减少内存使用:
const FlyweightIcon = React.memo(({ type }) => {
const icons = {
success: <SuccessIcon />,
error: <ErrorIcon />,
warning: <WarningIcon />
};
return icons[type];
});
// 大量重复使用
{items.map(item => (
<FlyweightIcon key={item.id} type={item.status} />
))}
命令模式封装操作
命令模式将操作封装为对象:
class Calculator {
constructor() {
this.current = 0;
this.history = [];
}
execute(command) {
this.current = command.execute(this.current);
this.history.push(command);
}
undo() {
const command = this.history.pop();
this.current = command.undo(this.current);
}
}
class AddCommand {
constructor(value) {
this.value = value;
}
execute(current) {
return current + this.value;
}
undo(current) {
return current - this.value;
}
}
// React组件中使用
const CalcUI = () => {
const [calc] = useState(new Calculator());
const [result, setResult] = useState(0);
const handleAdd = (value) => {
calc.execute(new AddCommand(value));
setResult(calc.current);
};
const handleUndo = () => {
calc.undo();
setResult(calc.current);
};
return (
<div>
<div>结果: {result}</div>
<button onClick={() => handleAdd(5)}>加5</button>
<button onClick={handleUndo}>撤销</button>
</div>
);
};
模板方法模式定义算法骨架
模板方法模式在React中可用于定义组件生命周期:
abstract class BaseComponent extends React.Component {
// 模板方法
componentDidMount() {
this.init();
this.fetchData();
this.setupListeners();
}
abstract init(): void;
abstract fetchData(): void;
abstract setupListeners(): void;
}
class ConcreteComponent extends BaseComponent {
init() {
console.log('初始化...');
}
fetchData() {
console.log('获取数据...');
}
setupListeners() {
console.log('设置监听...');
}
}
空对象模式处理默认情况
空对象模式可避免null检查:
const NullUser = {
name: '访客',
isAuthenticated: false,
hasPermission: () => false
};
const UserGreeting = ({ user = NullUser }) => (
<div>
{user.isAuthenticated ? (
<h1>欢迎回来, {user.name}!</h1>
) : (
<h1>请登录</h1>
)}
</div>
);
// 使用时不需担心user为null
<UserGreeting />
中介者模式协调组件通信
中介者模式简化组件间通信:
const ChatMediator = {
participants: [],
register(participant) {
this.participants.push(participant);
},
send(message, sender) {
this.participants.forEach(participant => {
if (participant !== sender) {
participant.receive(message);
}
});
}
};
class User extends React.Component {
state = { messages: [] };
componentDidMount() {
ChatMediator.register(this);
}
receive = (message) => {
this.setState(prev => ({
messages: [...prev.messages, message]
}));
};
send = () => {
ChatMediator.send(this.props.name + ': ' + this.inputRef.value, this);
};
render() {
return (
<div>
<div>{this.state.messages.join('\n')}</div>
<input ref={ref => this.inputRef = ref} />
<button onClick={this.send}>发送</button>
</div>
);
}
}
状态模式管理复杂状态
状态模式简化状态转换逻辑:
class TrafficLightState {
constructor(light) {
this.light = light;
}
change() {}
}
class RedState extends TrafficLightState {
change() {
console.log('红灯 -> 绿灯');
this.light.setState(new GreenState(this.light));
}
}
class GreenState extends TrafficLightState {
change() {
console.log('绿灯 -> 黄灯');
this.light.setState(new YellowState(this.light));
}
}
class TrafficLight extends React.Component {
state = { currentState: new RedState(this) };
setStateClass(state) {
this.setState({ currentState: state });
}
handleChange = () => {
this.state.currentState.change();
};
render() {
return (
<div>
<button onClick={this.handleChange}>切换信号灯</button>
</div>
);
}
}
访问者模式处理复杂数据结构
访问者模式适合处理异构元素集合:
class ElementVisitor {
visit(element) {
console.log('默认访问者');
}
}
class JSONVisitor extends ElementVisitor {
visit(element) {
return JSON.stringify(element);
}
}
class ReactElement {
accept(visitor) {
return visitor.visit(this);
}
}
class UserElement extends ReactElement {
constructor(props) {
super();
this.props = props;
}
}
// 使用访问者
const user = new UserElement({ name: '张三', age: 30 });
const json = user.accept(new JSONVisitor());
console.log(json); // 输出JSON字符串
责任链模式处理请求
责任链模式允许多个对象处理请求:
class Handler {
constructor(successor = null) {
this.successor = successor;
}
handle(request) {
if (this.successor) {
return this.successor.handle(request);
}
return null;
}
}
class AuthHandler extends Handler {
handle(request) {
if (request.user?.isAuthenticated) {
return super.handle(request);
}
throw new Error('未授权');
}
}
class LoggingHandler extends Handler {
handle(request) {
console.log('请求:', request);
return super.handle(request);
}
}
// React组件中使用
const ProtectedComponent = () => {
const handlerChain = new AuthHandler(new LoggingHandler());
const handleAction = () => {
try {
handlerChain.handle({ user: { isAuthenticated: true } });
// 执行业务逻辑
} catch (error) {
console.error(error);
}
};
return <button onClick={handleAction}>执行操作</button>;
};
桥接模式分离抽象与实现
桥接模式连接不同维度的变化:
// 实现部分
class Renderer {
render(shape) {}
}
class SVGRenderer extends Renderer {
render(shape) {
return `<svg>${shape.draw()}</svg>`;
}
}
// 抽象部分
class Shape {
constructor(renderer) {
this.renderer = renderer;
}
draw() {}
}
class Circle extends Shape {
draw() {
return this.renderer.render(this);
}
}
// React中使用
const ShapeRenderer = ({ type }) => {
const renderer = new SVGRenderer();
const shape = type === 'circle' ? new Circle(renderer) : null;
return <div dangerouslySetInnerHTML={{ __html: shape?.draw() }} />;
};
原型模式克隆对象
原型模式在React中可用于状态复制:
const initialFormState = {
values: {},
errors: {},
isSubmitting: false
};
function useForm(initialState = initialFormState) {
const [state, setState] = useState(initialState);
const reset = () => {
// 使用对象展开实现浅克隆
setState({ ...initialFormState });
};
const cloneState = () => {
// 深克隆实现
return JSON.parse(JSON.stringify(state));
};
return { state, setState, reset, cloneState };
}
对象池模式管理资源
对象池模式优化频繁创建销毁的对象:
class TooltipPool {
constructor() {
this.pool = [];
}
get() {
return this.pool.pop() || document.createElement('div');
}
release(tooltip) {
tooltip.style.display = 'none';
this.pool.push(tooltip);
}
}
// React组件中使用
const Tooltip = ({ text }) => {
const pool = useRef(new TooltipPool());
const [tooltip, setTooltip] = useState(null);
useEffect(() => {
const element = pool.current.get();
element.textContent = text;
element.style.display = 'block';
setTooltip(element);
return () => {
pool.current.release(element);
};
}, [text]);
return <div ref={ref => ref?.appendChild(tooltip)} />;
};
上一篇: 沙箱模式(Sandbox)的安全执行环境
下一篇: Vue的响应式系统与设计模式