003-HOC与函数柯里化

深入解析高阶组件(HOC)与柯里化函数实现

一、高阶组件(HOC)详解

1. 核心概念

高阶组件(Higher-Order Component)是React中用于复用组件逻辑的高级技术,本质上是一个函数:

  • 输入:一个组件
  • 输出:一个新的增强组件
1
const EnhancedComponent = higherOrderComponent(WrappedComponent);

2. 核心特征

  • 非侵入性:不修改原组件,通过组合扩展功能
  • 逻辑复用:抽离通用逻辑(如鉴权、日志、数据获取)
  • 渲染劫持:控制被包裹组件的渲染行为
  • Props代理:操作传入组件的props

3. 常见HOC类型

类型 功能 示例
Props代理 增删改props 注入额外属性
继承反转 继承原组件控制渲染 条件渲染控制
状态抽象 管理公共状态 表单状态管理
样式增强 添加样式逻辑 withStyles

二、React中的实际HOC案例

1. Redux的connect

1
2
3
4
const ConnectedComponent = connect(
mapStateToProps,
mapDispatchToProps
)(Component);
  • 功能:连接React组件与Redux store
  • 原理:通过Context注入store数据

2. React Router的withRouter

1
const ComponentWithRouter = withRouter(Component);
  • 功能:注入路由对象(history, location, match)
  • 使用场景:非路由组件访问路由信息

3. 自定义HOC示例:权限控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function withAuth(WrappedComponent) {
return class extends React.Component {
state = { hasPermission: false };

async componentDidMount() {
const user = await fetchUser();
this.setState({
hasPermission: user.role === 'admin'
});
}

render() {
return this.state.hasPermission
? <WrappedComponent {...this.props} />
: <div>无访问权限</div>;
}
}
}

// 使用
const AdminPanel = withAuth(PanelComponent);

三、函数柯里化实现:add(1)(2)(3)

1. 柯里化概念

柯里化(Currying)是把多参数函数转换为一系列单参数函数的技术:

1
2
3
4
5
// 普通函数
add(1, 2, 3);

// 柯里化函数
add(1)(2)(3)();

2. 实现方案对比

方案 特点 适用场景
递归存储 闭包保存中间值 基础实现
隐式转换 利用valueOf 简洁调用
参数收集 支持无限链式 最通用

3. 完整实现代码(支持无限链式调用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function add(x) {
// 存储所有参数的数组
let sum = x;

// 定义内部函数
function innerAdd(y) {
if (y !== undefined) {
sum += y;
return innerAdd; // 返回自身支持链式调用
}
return sum; // 无参调用时返回结果
}

// 重写valueOf实现隐式转换
innerAdd.valueOf = () => sum;

// 重写toString便于调试
innerAdd.toString = () => `CurriedSum(${sum})`;

return innerAdd;
}

4. 使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 基础用法
console.log(add(1)(2)(3)()); // 6

// 隐式转换
console.log(+add(1)(2)(3)); // 6 (触发valueOf)
console.log(add(1)(2)(3) + 4); // 10

// 无限链式
const sum = add(1)(2)(3)(4)(5);
console.log(sum()); // 15

// 分段调用
const addTwo = add(1)(1);
console.log(addTwo(3)()); // 5
console.log(addTwo(5)()); // 7

5. 实现原理图解

1
2
3
4
5
6
7
8
9
10
11
graph TD
A[调用add(1)] --> B[创建闭包环境<br>sum=1]
B --> C[返回innerAdd函数]
C --> D[调用(2)]
D --> E[sum=1+2=3]
E --> F[返回innerAdd]
F --> G[调用(3)]
G --> H[sum=3+3=6]
H --> I[返回innerAdd]
I --> J[无参调用]
J --> K[返回sum=6]

四、HOC与柯里化的关联

1. 设计模式相似性

概念 HOC 柯里化
核心思想 组件增强 函数转换
输入输出 组件 → 组件 函数 → 函数
实现方式 闭包保存状态 闭包保存参数

2. React中的结合应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 柯里化风格HOC工厂
const withFeature = (featureName) => (WrappedComponent) => {
return class extends React.Component {
featureMethod() {
console.log(`执行${featureName}功能`);
}

render() {
return <WrappedComponent
{...this.props}
featureMethod={this.featureMethod}
/>;
}
}
}

// 使用
const withLogger = withFeature('日志记录');
const EnhancedComponent = withLogger(MyComponent);

五、HOC最佳实践

  1. 命名规范:使用with前缀(withAuth, withLogger)
  2. 传递无关props:确保原组件props透传
  3. 避免修改原组件:使用组合而非继承
  4. 正确处理ref:使用React.forwardRef
    1
    2
    3
    4
    5
    function withLogging(WrappedComponent) {
    return React.forwardRef((props, ref) => {
    return <WrappedComponent {...props} ref={ref} />;
    });
    }
  5. 组合多个HOC:使用compose函数
    1
    2
    3
    4
    5
    6
    const enhance = compose(
    withAuth,
    withLogger,
    withAnalytics
    );
    const EnhancedComponent = enhance(BaseComponent);

六、HOC的现代替代方案

方案 优势 适用场景
React Hooks 逻辑复用更简洁 函数组件
Render Props 灵活共享代码 组件间逻辑共享
Context API 跨层级数据传递 主题/用户信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 使用Hooks替代HOC示例
function useAuth() {
const [user, setUser] = useState(null);

useEffect(() => {
fetchUser().then(setUser);
}, []);

return {
isAdmin: user?.role === 'admin'
};
}

// 组件内使用
function AdminPanel() {
const { isAdmin } = useAuth();
return isAdmin ? <Panel /> : <DeniedView />;
}

总结

  1. HOC本质:组件工厂函数,实现逻辑复用
  2. 核心价值:解耦、复用、增强组件功能
  3. 柯里化实现:利用闭包保存中间状态,支持链式调用
  4. 现代演进:Hooks逐渐成为主流替代方案
  5. 适用场景
    • HOC:跨组件复用逻辑(如鉴权、埋点)
    • 柯里化:参数分步传递的场景(如配置初始化)

通过HOC和柯里化的组合使用,可以构建出高度灵活且可复用的React应用架构,同时保持代码的简洁性和可维护性。