资讯详情

Refine useSelect Hook 实战指南:将 Ant Design Select 与资源数据无缝绑定

📅 2026/9/13 1:21:44 | 华诺云谱 👁 阅读
Refine useSelect Hook 实战指南:将 Ant Design Select 与资源数据无缝绑定
Refine useSelect Hook 实战指南将 Ant Design Select 与资源数据无缝绑定【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refineuseSelect是 Refine 面向 Ant Design 提供的字段级 Hook用于把一个资源resource中的记录直接转换成 Ant DesignSelect组件的选项options。它内部基于useList完成数据拉取并自动处理加载态、搜索含防抖、排序、过滤与分页。读完本文你将掌握useSelect的完整属性体系、返回值语义、与useForm的组合方式以及它在 refinedev/antd 源码 与 refinedev/core 源码 中的真实实现原理。本文以 documentation/docs/ui-integrations/ant-design/hooks/use-select/index.md 及其配套的可运行示例_basic-usage-live-preview.md、_on-search-live-preview.md、_sort-live-preview.md、_default-value-live-preview.md、_crud-live-preview.md为主体展开。useSelect 是什么定位与数据流useSelect允许你在资源记录需要作为下拉选项时管理 Ant Design 的Select组件。它把取数据这件事完全交给 Refine主查询走useList调用dataProvider.getList用于拉取选项列表当配置了defaultValue时会额外走useMany调用dataProvider.getMany用于补齐默认选中项的数据。用一句话概括你只需要声明资源名useSelect负责把数据变成{ label, value }形状的 options并把这些 options 连同搜索、加载态一起打包成selectProps直接展开到Select上即可。关于useList的更多细节可参考 useList 文档。快速上手基础用法先看一个完整的入门示例——在创建文章页面中从categories资源加载分类下拉选项import { useSelect } from refinedev/antd; import { Select } from antd; interface ICategory { id: number; title: string; } const PostCreate: React.FC () { const { selectProps } useSelectICategory({ resource: categories, }); return ( Select placeholderSelect a category style{{ width: 300 }} {...selectProps} / ); };把selectProps展开到Select上即获得了options由categories资源记录转换而成的{ label, value }[]onSearch内置的搜索回调默认对title字段做contains过滤loading数据拉取中的加载状态showSearch: true与filterOption: false开启搜索框但把过滤逻辑交给服务端由onSearch触发的getList请求完成。这些默认行为在 packages/antd/src/hooks/fields/useSelect/index.ts 中可见一斑。重要useSelect 不管理选中值useSelect主要面向数据获取管理 options、loading、分页不管理Select的受控状态当前选中值。如果独立使用Select你需要自己用useState维护value/onChange如果与 Ant Design Form 一起使用则把Select放进Form.Item由表单负责选中值。核心属性配置详解resource必填resource会经由useList作为参数传给dataProvider的getList方法。它通常被当作 API 端点路径使用但具体如何解释取决于你的getList实现参见 创建 data provider 文档。useSelect({ resource: categories, });如果存在多个同名资源可以传入identifier来替代name作为资源的匹配键data provider 方法仍使用Refine /组件中定义的name工作。相关说明见Refine /组件的identifier章节。optionLabel 与 optionValue用于自定义选项的value与label。默认值分别为optionLabel title、optionValue iduseSelectICategory({ resource: products, optionLabel: name, optionValue: productId, });这两个属性支持Object path 嵌套访问lodash 风格即get(item, path)const { options } useSelect({ resource: categories, optionLabel: nested.title, optionValue: nested.id, });也支持传入函数函数会收到item参数便于拼接显示const { options } useSelect({ optionLabel: (item) ${item.firstName} ${item.lastName}, optionValue: (item) item.id, });从源码看core 层通过getOptionLabel/getOptionValue两个useCallback统一处理字符串路径与函数两种形态见 packages/core/src/hooks/useSelect/index.ts。searchField指定onSearch时按哪个字段进行搜索const { onSearch } useSelect({ searchField: name }); onSearch(John); // 按 name 字段、值为 John 搜索默认规则当optionLabel是字符串时沿用optionLabel的值否则回退到title字段// optionLabel 为字符串时搜索 name 字段 const { onSearch } useSelect({ optionLabel: name }); onSearch(John); // 按 name 搜索 // optionLabel 为函数时回退到 title 字段 const { onSearch } useSelect({ optionLabel: (item) ${item.id} - ${item.name}, }); onSearch(John); // 按 title 搜索sorters控制选项的展示顺序会经useList传给getList最终以排序查询参数的形式发给 APIuseSelect({ sorters: [ { field: title, order: asc, }, ], });你甚至可以把排序字段与顺序做成受控状态实现一键切换排序const [order, setOrder] React.useStateasc | desc(asc); const { selectProps } useSelectICategory({ resource: categories, sorters: [ { field: title, order, }, ], }); return ( Select placeholder{Ordered Categories: ${order}} style{{ width: 300 }} {...selectProps} / Button onClick{() setOrder(order asc ? desc : asc)} Toggle Order /Button / );sorter的完整形态可参考 CrudSorting 接口文档。filters过滤展示的选项同样会经useList传给getListuseSelect({ filters: [ { field: isActive, operator: eq, value: true, }, ], });完整的过滤器形态见 CrudFilters 接口文档。defaultValue保证默认值出现在选项中当选项数量很多、需要分页时某个默认选中值可能不在当前可见列表中导致Select显示异常。为此useSelect会在配置defaultValue时额外发起一次useMany查询把默认值对应的记录补充进 options。defaultValue可以是单个值也可以是数组useSelect({ defaultValue: 1, // 或 [1, 2] });:::info 注意defaultValue并不设置默认选中项它只保证该值存在于选项中。要真正默认选中请把值传给Select的valueprop 或useFormconst form useForm({ defaultValues: { category: { id: 1 }, // 默认选中值 }, }); const { selectProps } useSelect({ resource: categories, defaultValue: [1], // 确保默认值出现在选项中 });:::selectedOptionsOrder控制defaultValue对应的已选选项在列表中的位置in-place已选选项排在底部默认值selected-first已选选项排在顶部。useSelect({ defaultValue: 1, // 或 [1, 2] selectedOptionsOrder: selected-first, // in-place | selected-first });这背后依赖useMany查询可参考 useMany 文档。debounce对onSearch函数做防抖处理单位为毫秒core 层默认值为300useSelect({ resource: categories, debounce: 500, });queryOptions透传给内部useQuery的额外选项例如控制重试次数useSelect({ queryOptions: { retry: 3, }, });pagination分页配置会经useList传给getList用于发送分页查询参数。它支持以下子项currentPage指定页码useSelect({ pagination: { currentPage: 2, }, });pageSize每页条数useSelect({ pagination: { pageSize: 20, }, });modeoff、client或server决定是否使用服务端分页useSelect({ pagination: { mode: off, }, });值得注意的是当pageSize未指定时core 层默认使用10见 packages/core/src/hooks/useSelect/index.ts。defaultValueQueryOptions当传入defaultValue时会调用useMany查询已选记录。defaultValueQueryOptions用来定制这次查询的选项如果未传入defaultValue则会回退使用queryOptions中的值const { options } useSelect({ resource: categories, defaultValueQueryOptions: { onSuccess: (data) { console.log(triggers when on query return on success); }, }, });onSearch给 options 加上 AutocompleteonSearch允许为选项加入 Autocomplete自动补全能力。它的签名是(value: string) CrudFilter[]即输入值 → 过滤条件import { useSelect } from refinedev/antd; import { Select } from antd; interface ICategory { id: number; title: string; } const PostCreate: React.FC () { const { selectProps } useSelectICategory({ resource: categories, onSearch: (value) [ { field: title, operator: contains, value, }, ], }); return ( Select placeholderSelect a category style{{ width: 300 }} {...selectProps} / ); };注意一旦使用onSearch它会覆盖已有的filters搜索条件会整体替换原过滤条件。原因是 core 层在发起useList时执行filters.concat(search)而onSearch返回的数组会整体写入search状态见 packages/core/src/hooks/useSelect/index.ts。客户端过滤不请求服务端如果你希望完全在客户端过滤选项把onSearch显式传为undefined并设置filterOption与optionFilterPropconst { selectProps } useSelect({ resource: categories, }); Select {...selectProps} onSearch{undefined} filterOption{true} optionFilterProplabel // 或 value /;metameta用于向 data provider 方法传递额外信息典型用途包括针对特定场景定制 data provider 方法用纯 JavaScript 对象JSON生成 GraphQL 查询。例如向getList传递自定义请求头useSelect({ meta: { headers: { x-meta-data: true }, }, }); const myDataProvider { //... getList: async ({ resource, pagination, sorters, filters, meta, }) { const headers meta?.headers ?? {}; const url ${apiUrl}/${resource}; //... const { data, headers } await httpClient.get(${url}, { headers }); return { data, }; }, //... };更系统的说明见 General Concepts 的 meta 概念章节。dataProviderName当项目配置了多个 data provider 时用它指定使用哪一个useSelect({ dataProviderName: second-data-provider, });successNotification 与 errorNotification在数据成功/失败拉取后useSelect可以调用NotificationProvider的open方法展示通知。这两个 prop 用于自定义通知内容依赖 NotificationProvideruseSelect({ successNotification: (data, values, resource) { return { message: ${data.title} Successfully fetched., description: Success with no errors, type: success, }; }, });useSelect({ errorNotification: (data, values, resource) { return { message: Something went wrong when getting ${data.id}, description: Error, type: error, }; }, });实时更新相关liveMode / onLiveEvent / liveParams以下属性依赖 LiveProviderliveMode收到相关 live 事件后是否自动auto或手动manual更新数据useSelect({ liveMode: auto, });onLiveEvent订阅到新事件时执行的回调useSelect({ onLiveEvent: (event) { console.log(event); }, });liveParams传给liveProvider的subscribe方法的参数。当useSelect挂载时它会向subscribe方法传递channel、resource等参数从而实现实时订阅。overtimeOptions超时加载提示当你希望在请求耗时过长时展示加载提示可以传入overtimeOptions。interval是毫秒级的时间间隔onInterval是每个间隔触发的回调const { overtime } useSelect({ //... overtimeOptions: { interval: 1000, onInterval(elapsedInterval) { console.log(elapsedInterval); }, }, }); console.log(overtime.elapsedTime); // undefined, 1000, 2000, 3000 4000, ... // 用法示例 { elapsedTime 4000 divthis takes a bit longer than expected/div; }overtime.elapsedTime表示已耗时毫秒数请求完成后会变为undefined。返回值速查返回值说明selectProps可直接展开到Select的 Ant Design 属性options、onSearch、loading、showSearch、filterOptionquery列表查询结果useList对应的QueryObserverResultdefaultValueQuerydefaultValue记录的查询结果useMany对应结果defaultValueQueryOnSuccess默认值查询成功时的回调overtime超时加载属性含elapsedTime实战问答高频场景速查如何给 options 加搜索Autocomplete使用onSearch它负责设置搜索值并触发服务端过滤。完整示例见上文 onSearch 一节以及配套的_on-search-live-preview.md示例。如何确保defaultValue出现在选项中有时我们只拿到id却希望它在选择框中被显示为已选。useSelect会通过useMany拉取该记录数据并标记为已选示例见 _default-value-live-preview.mdconst { selectProps } useSelectICategory({ resource: categories, defaultValue: 11, });如何修改 options 的 label 和 value使用optionLabel与optionValue默认是title与id。要改成name和categoryIduseSelect({ optionLabel: name, optionValue: categoryId, });可以手动创建 options 吗有时仅靠optionLabel/optionValue不够灵活可以直接从query返回值手动构造 optionsconst { query } useSelect(); const options query.data?.data.map((item) ({ label: item.title, value: item.id, })); return Select options{options} /;如何与 CRUD 组件和 useForm 配合把selectProps放进Form.Item与useForm的formProps、saveButtonProps组合即可示例见 _crud-live-preview.mdimport { Create, useSelect, useForm } from refinedev/antd; import { Form, Select } from antd; interface ICategory { id: number; title: string; } const PostCreate: React.FC () { const { formProps, saveButtonProps } useFormICategory(); const { selectProps } useSelectICategory({ resource: categories, }); return ( Create saveButtonProps{saveButtonProps} Form {...formProps} layoutvertical Form.Item labelCategory placeholderSelect a category name{[category, id]} rules{[ { required: true, }, ]} Select {...selectProps} / /Form.Item /Form /Create ); };源码级原理剖析第一层refinedev/antd 的轻量封装packages/antd/src/hooks/fields/useSelect/index.ts 中的useSelect只是一个适配层它调用 core 层的useSelectCore拿到query、defaultValueQuery、onSearch、options再组装成 Ant Design 的selectPropsreturn { selectProps: { options, onSearch, loading: defaultValueQuery.query.isFetching, showSearch: true, filterOption: false, }, query, defaultValueQuery: defaultValueQuery.query, };可以看到加载态同时考虑了默认值查询的isFetching并默认开启showSearch、关闭客户端filterOption把过滤交给服务端搜索。第二层refinedev/core 的核心逻辑packages/core/src/hooks/useSelect/index.ts 实现了真正的数据编排两个查询并行useMany拉取defaultValue记录与useList拉取选项列表同时发起。useMany仅在defaultValues.length 0且enabled为 true 时启用L286-L298默认值归一化defaultValue统一转为数组defaultValuesL249-L251搜索防抖onSearch用lodash/debounce包裹debounce默认300ms若用户提供了onSearch函数则完全采用其返回的过滤数组否则自动生成{ field: searchField, operator: contains, value }条件L343-L363选项合并去重通过uniqBy(..., value)把主列表 options 与默认值 selectedOptions 合并selectedOptionsOrder决定合并顺序in-place时默认值在后selected-first时在前L326-L335标签解析getOptionLabel/getOptionValue使用lodash/get支持点分路径也支持函数形态L216-L236Overtime 计时useLoadingOvertime同时监听主查询与默认值查询的isFetchingL320-L324。测试佐证useSelect的行为由 packages/antd/src/hooks/fields/useSelect/index.spec.ts 中的测试用例覆盖涉及资源解析、optionLabel/optionValue、排序、过滤等场景可作为自定义改造时的行为参照。配套示例项目仓库提供了两个可直接运行、对照学习的完整示例examples/field-antd-use-select-basicuseSelect基础用法基本选项绑定、搜索、默认值等examples/field-antd-use-select-infinite无限滚动加载示例演示选项很多时如何结合分页滚动加载。小结useSelect是 Refine Ant Design 组合下处理下拉选项的最高频 Hook 之一它用一行resource声明替代了手写getList请求、状态管理与选项映射的重复劳动并通过onSearch、sorters、filters、defaultValue、pagination等属性覆盖了搜索、排序、过滤、默认值补齐、分页等几乎全部真实业务场景。理解其useList拉选项 useMany补默认值 debounce 搜索 uniqBy 合并的底层实现见 packages/core/src/hooks/useSelect/index.ts能帮助你在需要深度定制时快速定位扩展点。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。