news 2026/9/13 4:53:13

Refine v5 中 useDrawer Hook 的使用与底层原理:轻松掌控 Ant Design Drawer

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Refine v5 中 useDrawer Hook 的使用与底层原理:轻松掌控 Ant Design Drawer

Refine v5 中 useDrawer Hook 的使用与底层原理:轻松掌控 Ant Design Drawer

【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine

useDrawer@refinedev/antd提供的状态管理 Hook,用于封装 Ant Design 的<Drawer>侧滑抽屉组件的打开、关闭与受控属性,让你无需手写useStateonClose样板代码即可管理抽屉。本文将从基础用法、返回值与参数、源码实现、测试验证以及与useDrawerForm的衔接四个层面,带你完整掌握这一 Hook 的实战姿势与内部机制。

什么是 useDrawer

在 Refine 的 Ant Design 集成中,useDrawer是一个专为 Ant Design Drawer 组件设计的 Hook。它的核心职责是:

  • 通过show/close两个函数控制抽屉的打开与关闭;
  • 通过drawerProps一次性提供<Drawer>组件所需的全部受控属性(openonClose),直接展开(spread)到组件上即可生效。

最基本的调用方式如下:

const { show, close, drawerProps } = useDrawer();

拿到返回值后,将drawerProps解构到<Drawer />组件上,再用showclose控制可见性即可。

从源码类型定义可以确认其返回值结构(见 useDrawer/index.tsx):

export type useDrawerReturnType = { drawerProps: DrawerProps; } & Omit<useModalReturnType, "visible">;

也就是说,返回值由两部分组成:drawerProps(Ant Design 的DrawerProps类型)加上来自@refinedev/coreuseModal返回类型中去掉visible之后的showclose

快速上手:在列表页中弹出一个抽屉

原文档给出了一段最简示例(src/pages/posts/list.tsx),我们在此基础上补充注释和细节:

import { useDrawer } from "@refinedev/antd"; import { Drawer, Button } from "antd"; export const PostList: React.FC = () => { const { show, drawerProps } = useDrawer(); return ( <> <Button onClick={show}>Show Drawer</Button> <Drawer {...drawerProps}> <p>Drawer Content</p> </Drawer> </> ); };

工作流程如下:

  1. 页面上渲染一个按钮,把show绑定到它的onClick回调;
  2. 用户点击按钮,show()内部将可见状态置为true
  3. drawerProps中的open属性随之变为true<Drawer>弹出;
  4. 用户点击遮罩、关闭按钮或按 ESC 键时,Ant Design 的 Drawer 会触发onClose,而drawerProps内置的onClose会调用close()把状态置回false,抽屉收起。

返回值详解:show / close / drawerProps

原文档的 API Reference 表格中showclose的描述存在笔误(两者说明被写反),这里依据仓库源码给出准确对照:

返回值类型说明(依据源码)
show() => void打开抽屉。内部调用useModal返回的show,将可见状态置为true
close() => void关闭抽屉。内部调用useModal返回的close,将可见状态置为false
drawerPropsDrawerProps传给<Drawer />的受控属性集合,包含open(当前可见状态)与onClose(默认先透传用户自定义的onClose,再执行close()

drawerProps 的合并逻辑

drawerProps并非原样透传,而是经过了一层合并处理,源码如下(useDrawer/index.tsx):

return { drawerProps: { ...drawerProps, onClose: (e: React.MouseEvent | React.KeyboardEvent) => { drawerProps.onClose?.(e); close(); }, open: visible, }, show, close, };

这里有三点值得注意:

  • open: visible覆盖你传入的open,确保抽屉可见性始终由 Hook 内部状态驱动,避免受控/非受控状态打架;
  • onClose会被包装:先调用你自定义的onClose(如果有),再调用close()。这意味着你可以在关闭前挂载自己的清理逻辑,同时不必担心抽屉无法正常关闭;
  • 传入的其余DrawerProps(如widthtitleplacement等)会通过展开运算符保留。

参数详解:初始化默认可见性

useDrawer接受一个可选的配置对象:

useDrawer({ drawerProps: { open: true, // 初始状态直接打开抽屉 width: 500, title: "Post Detail", }, });

唯一的参数是drawerProps,类型为 Ant Design 的DrawerProps。其中只有open会被 Hook 特殊对待——源码中通过useModal({ defaultVisible: drawerProps.open })把它作为抽屉的初始可见状态读取(见 useDrawer/index.tsx):

export const useDrawer = ({ drawerProps = {}, }: useDrawerProps = {}): useDrawerReturnType => { const { show, close, visible } = useModal({ defaultVisible: drawerProps.open, }); // ... };

也就是说,open: true表示抽屉挂载时默认展开;未传时默认收起。其余DrawerProps会原样合并进返回的drawerProps

源码剖析:useDrawer 与 useModal 的分层设计

useDrawer本身没有重复实现状态逻辑,而是复用了@refinedev/core中的通用useModalHook,这是典型的"核心层 + UI 层"分层设计。

useModal的实现非常精简(packages/core/src/hooks/modal/useModal/index.tsx):

export const useModal = ({ defaultVisible = false, }: useModalProps = {}): useModalReturnType => { const [visible, setVisible] = useState(defaultVisible); const show = useCallback(() => setVisible(true), [visible]); const close = useCallback(() => setVisible(false), [visible]); return { visible, show, close, }; };

可以看到:

  • 可见状态就是一个useState,初始值由defaultVisible决定;
  • showcloseuseCallback缓存,仅依赖visible
  • 返回的visibleuseDrawer中被映射为drawerProps.open,因此useDrawer的返回值刻意用Omit<useModalReturnType, "visible">去掉了visible,避免调用方在openvisible之间产生混淆。

这条调用链可以概括为:useDrawer(Ant Design 适配层)→useModal(核心通用状态层)→useState。理解这一点后,你在排查抽屉"打不开/关不上"问题时,就能直接定位到是show/close未被触发,还是drawerProps被外部覆盖了open

测试验证:行为边界有据可查

仓库为useDrawer提供了完整的单元测试(index.spec.ts),覆盖了以下关键行为,这些行为可以作为你使用时的心智模型:

  1. 初始不可见:不传参调用useDrawer()drawerProps.openfalse
  2. 传入open: true初始可见useDrawer({ drawerProps: { open: true } })drawerProps.opentrue
  3. show()打开:调用show()open变为true
  4. close()关闭:先show()close()open回到false
  5. 自定义onClose被调用且抽屉关闭:传入onClose后触发drawerProps.onClose,自定义回调恰好被调用 1 次,同时抽屉关闭;
  6. 未传onClose时关闭:无自定义onClose时触发关闭同样生效。

第 5、6 条直接印证了上文提到的onClose包装逻辑:无论你是否自定义关闭回调,抽屉都能正常收起。

进阶衔接:useDrawerForm 与抽屉表单

单纯的useDrawer适合展示型抽屉(如详情展示、自定义交互内容)。如果你需要"在抽屉里编辑表单",Refine 提供了更高层的useDrawerForm,它内部正是基于useDrawer构建的(见 useDrawerForm.ts):

const { show, close, drawerProps } = useDrawer({ drawerProps: { open: defaultVisible, }, });

useDrawerFormuseDrawer的基础上额外整合了:

  • formProps:Ant Design 表单受控属性;
  • saveButtonProps/deleteButtonProps:保存、删除按钮属性;
  • formLoading:表单加载状态;
  • 默认的抽屉规格:width: "500px"forceRender: true
  • syncWithLocation:把抽屉打开状态和记录 id 同步到 URL 查询参数,刷新/分享后状态可恢复。

仓库中的可运行示例 examples/form-antd-use-drawer-form/src/pages/posts/list.tsx 展示了在同一列表页中同时管理"创建抽屉"与"编辑抽屉"的典型写法:

// 创建抽屉 const { formProps: createFormProps, drawerProps: createDrawerProps, show: createDrawerShow, saveButtonProps: createSaveButtonProps, } = useDrawerForm<IPost>({ action: "create", syncWithLocation: true, }); // 编辑抽屉 const { formProps: editFormProps, drawerProps: editDrawerProps, show: editDrawerShow, saveButtonProps: editSaveButtonProps, deleteButtonProps, id, formLoading: editFormLoading, } = useDrawerForm<IPost>({ action: "edit", syncWithLocation: true, });

列表的"新建"按钮调用createDrawerShow(),每行的"编辑"按钮调用editDrawerShow(record.id)传入记录 id,两个<Drawer>分别展开createDrawerPropseditDrawerProps。想深入了解,可继续阅读 use-drawer-form 文档。

小结

  • useDrawer用约 30 行代码把 Ant DesignDrawer的受控逻辑封装干净,show/close/drawerProps三个返回值各司其职;
  • 底层复用@refinedev/coreuseModalopen状态与onClose行为均有单测保障,边界行为清晰可查;
  • 纯展示用useDrawer,抽屉内嵌表单用useDrawerForm,两者在同一调用链上,可以平滑过渡升级。

【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 4:49:37

电子洁净库房温湿度均一性WiFi网格化监控方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 4:49:07

darktable 新手上手指南:从灰暗 RAW 到成片只需 4 步

darktable 新手上手指南&#xff1a;从灰暗 RAW 到成片只需 4 步 【免费下载链接】darktable darktable is an open source photography workflow application and raw developer 项目地址: https://gitcode.com/GitHub_Trending/da/darktable 拍回来的 RAW 文件又灰又闷…

作者头像 李华
网站建设 2026/9/13 4:46:57

Symfony 命令行测试 5 个场景实战,稳定不翻车

Symfony 命令行测试 5 个场景实战&#xff0c;稳定不翻车 【免费下载链接】nuclei-templates Community curated list of templates for the nuclei engine to find security vulnerabilities. 项目地址: https://gitcode.com/GitHub_Trending/nu/nuclei-templates 测一…

作者头像 李华
网站建设 2026/9/13 4:44:07

SDD规范驱动开发:终结氛围编程的技术实践

1. 什么是SDD&#xff1f;它真能终结“氛围编程”这种玄学开发状态&#xff1f;“氛围编程”这个词&#xff0c;我第一次听是在2023年夏天&#xff0c;一个前端团队的晨会上。产品经理刚讲完需求&#xff0c;三位工程师已经各自打开终端、切分支、敲命令——没人写PRD&#xff…

作者头像 李华