React高阶组件(TS类型推导)
· 阅读需 3 分钟
React高阶组件
前言
-
HOC高阶组件本质上是一个函数,往往接收一个函数组件并返回一个新的组件,在这个新的组件中对传入的组件进行了一些额外的操作。(即对原来的的组件内容进行补充或者增强) -
在开发场景中,
HOC高阶组件往往充当着工具组件的角色,他并不侵入性的影响原来的组件。基于这个原则,在HOC中去组织一些复用性的代码逻辑,从而控制其子树UI的渲染。 -
与自定义
Hook不同,Hook只能将我们的代码逻辑抽离到一个地方,但并不能直接影响UI的渲染,而是通过Hook提供的内容自己去控制视图内容。
HOC的作用(不考虑反向继承,有侵入性影响)
- 负责补充传递
props。 - 直接在
HOC内部去控制原有组件的渲染(不改变原有组件的前提下)。
二者并非互斥的关系,HOC的核心就是由自己内部执行特定逻辑从而影响、控制原有组件的内容。
代码示例
目标示例: 哨兵进入视口时通知子组件(常见于无限滚动「快到底了」)。注意:isVisible 表示是否可见,不等于业务上的 isLoading(是否在请求中)。下面用 isVisible 注入,避免语义混淆。
- 补充 Props:
import { ComponentType, useEffect, useMemo, useRef, useState } from 'react';
type WithVisible = { isVisible?: boolean };
function ObserverHOC<P extends WithVisible>(Component: ComponentType<P>) {
const WrappedComponent = (props: Omit<P, 'isVisible'>) => {
const domRef = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);
const observer = useMemo(
() =>
new IntersectionObserver(entries => {
entries.forEach(entry => {
setIsVisible(entry.isIntersecting);
});
}),
[]
);
useEffect(() => {
const dom = domRef.current;
if (dom) observer.observe(dom);
return () => {
observer.disconnect();
};
}, [observer]);
return (
<div ref={domRef}>
<Component {...(props as P)} isVisible={isVisible} />
</div>
);
};
WrappedComponent.displayName = `ObserverHOC(${Component.displayName || Component.name || 'Component'})`;
return WrappedComponent;
}
export default ObserverHOC;
Omit<P, 'isVisible'> 表示包装后的组件不必再手动传 isVisible,由 HOC 注入。子组件内部仍可把 isVisible 当成「触发下一页加载」的信号,另用本地 state 管真正的 isLoading。

如果你漏传了Props,react也能提供相应的类型提示。

当然,这样需要你确定HOC本身传递的Props的类型和字段,保证其被包装的组件能够正确接收到。
- 控制
原有组件的渲染(不改变原有组件