在 React 中,类组件复用逻辑的方法主要包括高阶组件(Higher-Order Components, HOCs)和 Render Props。这两种模式都可以帮助我们在多个组件之间共享逻辑,但它们的实现方式和使用场景有所不同。
高阶组件(Higher-Order Components, HOCs)
高阶组件是一种用于复用组件逻辑的技术。它本质上是一个函数,接收一个组件并返回一个新的组件。HOCs 可以在不修改原组件的情况下增强组件的功能。
示例代码 假设我们有一个需求,需要在多个组件中添加用户认证逻辑。
import React, { Component } from 'react';
// 高阶组件
const withAuth = (WrappedComponent) => {
return class extends Component {
componentDidMount() {
// 模拟认证逻辑
const isAuthenticated = true; // 假设用户已认证
if (!isAuthenticated) {
// 未认证时的处理逻辑
console.log('User is not authenticated');
}
}
render() {
return <WrappedComponent {...this.props} />;
}
};
};
// 原始组件
class Dashboard extends Component {
render() {
return <div>Dashboard Content</div>;
}
}
// 包装后的组件
const DashboardWithAuth = withAuth(Dashboard);
export default DashboardWithAuth;
Render Props
Render Props 是一种通过一个函数将要渲染的内容传递给组件的技术。它允许我们在组件之间共享逻辑,而无需使用高阶组件。
示例代码 假设我们有一个需求,需要在多个组件中添加用户认证逻辑。
class AuthComponent extends Component {
componentDidMount() {
// 模拟认证逻辑
const isAuthenticated = true; // 假设用户已认证
if (!isAuthenticated) {
// 未认证时的处理逻辑
console.log('User is not authenticated');
}
}
render() {
return this.props.render();
}
};
// 原始组件
class Dashboard extends Component {
render() {
return <div>Dashboard Content</div>;
}
}
// 包装后的组件
const DashboardWithAuth = <AuthComponent render={() => <Dashboard />} />;
export default DashboardWithAuth;
比较与选择
高阶组件(HOCs)
优点:
- 可以在不修改现有组件的情况下增强组件功能。
- 适用于需要在多个组件中复用逻辑的场景。
缺点:
- 可能会导致“嵌套地狱”(Wrapper Hell),即组件层级过深,会造成比较多的问题,例如props丢失的问题,比如使用这样的代码
withAuth(withRouter(withUserStatus(UserDetail))),withAuth传递给UserDetail的某个prop可能在withUserStatus组件里面丢失或者被覆盖了。 - 隐藏了组件的实际层级,使得调试变得困难。
Render Props
优点:
- 更加灵活,可以动态决定渲染内容。
- 不会增加组件的层级。
缺点:
- 可能会导致“函数作为子组件”(Function as Child Component, FaCC)模式,使得代码结构不清晰。
- 每次渲染都会创建新的函数,可能会影响性能。
React Hooks逻辑复用(推荐)
同样使用React hooks实现上面的例子:
import { useEffect } from 'react';
const useAuth = () => {
useEffect(() => {
// 模拟认证逻辑
const isAuthenticated = true; // 假设用户已认证
if (!isAuthenticated) {
// 未认证时的处理逻辑
console.log('User is not authenticated');
}
}, []);
};
const Dashboard = () => {
useAuth();
return <div>Dashboard Content</div>;
};
export default Dashboard;
可以看到这种方式复用逻辑更简单,更直观,代码耦合度也更低。