文章

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

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

本文由作者按照 CC BY 4.0 进行授权