useRef、forwardRef和useImperativeHandle封装组件
useRef、forwardRef和useImperativeHandle封装组件
各API作用
- useRef:「使用方」创建一个
ref - forwardRef:
- 使用方法:「提供方」通过 forwardRef 包裹一个组件(class or function)。
- 用途:
- 除了外界传入的 props 外(因为 ref 不属于 props ),「组件内部」还能拿到外界挂在组件上的 ref,此时组件就可以操作这个ref了。
- 组件内部就可以将这个 ref 挂给内部的任意 DOM;或者作为一个 prop 传给下面组件,下面组件拿到 ref 后再挂给内部 DOM,或继续传递。
- useImperativeHandle:
- 「组件内部」能将内部属性、方法传递给上层的「使用方」。
代码结构设计
目的:对于基于 <Drawer /> 或者 <Modal /> 等封装的业务组件,不用再向其传递 visible + setVisible 回调,利用 ref 可以避免冗余 props 的传递。
代码核心实现
自定义hooks:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 获取常用卡片配置
*/
export const useNormalConfig = () => {
// 常用卡片ref
const ref = useRef() as MutableRefObject<NormalCardConfigRef>;
useEffect(() => {
// ...
}, [list]);
return {
ref,
// ...
};
};
页面组件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const PageComp = React.memo(() => {
const [carryType, setCarryType] = useState<number | string>(1);
// 常用卡片配置
const normalConfig = useNormalConfig();
return <div>
<NormalCardConfig
carryType={Number(carryType) || 1}
ref={normalConfig?.ref} // 传递ref
onOk={() => {
// ...
}}
/>
</div>
})
配置组件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 常用配置弹框。通过 forwardRef 接收外界传来的 ref
*/
const NormalCardConfig = forwardRef((props: NormalCardConfigProps, ref: Ref<NormalCardConfigRef>) => {
const { carryType, onOk } = props;
const [visible, setVisible] = useState<boolean>(false);
// 通过ref对外暴露方法
useImperativeHandle(ref, () => ({
show: () => setVisible(true),
hide: () => setVisible(false),
}));
return (
<Modal
// ...
>
// ...
</Modal>
);
});
参考链接
本文由作者按照 CC BY 4.0 进行授权