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 的传递。

link_preview

代码核心实现

自定义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>
);
});

参考链接

bookmark

bookmark

bookmark

1