ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Refine v5 useSelect Hook 实战指南:用 Ant Design Select 优雅管理资源下拉选项

Refine v5 useSelect Hook 实战指南:用 Ant Design Select 优雅管理资源下拉选项 Refine v5 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 v5 中面向 Ant Design 的专用 Hook它将资源记录Resource Records一键转换为Select组件所需的选项数据并内置搜索、排序、过滤、分页、默认值兜底与实时更新能力。读完本文你将掌握useSelect的全部属性、返回值与边界场景能直接在自己的管理后台中实现可搜索、可分页、可实时刷新的下拉选择框并理解其底层数据获取原理。什么是 useSelectuseSelect允许你在需要把某个资源resource的记录作为下拉选项时直接管理 Ant Design 的Select数据到达后自动映射为{ label, value }结构的选项数组。在 packages/antd/src/hooks/fields/useSelect/index.ts 中可以看到Ant Design 版本的useSelect是一个轻量包装层它调用refinedev/core中负责核心逻辑的useSelectCore并额外组装出可直接透传给Select的selectPropsreturn { selectProps: { options, onSearch, loading: defaultValueQuery.query.isFetching, showSearch: true, filterOption: false, }, query, defaultValueQuery: defaultValueQuery.query, };从源码可见selectProps已默认开启showSearch允许搜索并关闭filterOption避免纯客户端过滤与远程搜索冲突因此拿到selectProps后基本可以“零配置”接入Select。状态管理提醒useSelect的核心职责是数据获取管理选项、加载态、分页它不管理受控状态即当前选中的值。如果单独使用Select组件你需要自行通过useState或在使用 Ant Design Form 时借助Form.Item来管理value与onChange。基础用法以下是最基础的使用方式完整可运行示例见 _basic-usage-live-preview.mdimport { 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} / ); };useSelect会通过getList拉取categories资源的数据并把每条记录的title/id映射为选项的label/value。展开{...selectProps}后加载态、选项数据、搜索回调都会自动生效。从源码看核心实现位于 packages/core/src/hooks/useSelect/index.ts其中queryResult使用useList、defaultValueQueryResult使用useMany完成两条数据链路见下文defaultValue一节。实时更新Realtime Updates当useSelect挂载时它会向liveProvider的subscribe方法传入channel、resource等参数从而订阅实时事件需要先配置LiveProvider。配合liveMode、onLiveEvent、liveParams属性可以让下拉选项在数据变更时自动刷新实现多端协作场景下的实时同步。属性详解Propertiesresource是唯一必填属性其余属性均可按需配置。下面按文档顺序逐一展开并补充源码中的默认值与实现细节。resource必填resource会通过useList作为参数传给dataProvider的getList方法通常用作 API 端点路径具体语义取决于你在getList中如何处理resource参考创建 Data ProvideruseSelect({ resource: categories, });如果存在多个同名资源可以传入identifier代替name。它仅作为资源的匹配主键而 data provider 方法仍会使用Refine/组件中定义的name参考 Refine 组件 identifier 说明。测试 index.spec.ts 中的 two resources with same name, should pass resource meta according to identifier 用例验证了该行为。optionLabel 与 optionValue用于自定义选项的value和label默认值分别为optionLabel title、optionValue iduseSelectICategory({ resource: products, optionLabel: name, optionValue: productId, });两个属性都支持用 Object 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, });源码实现packages/core/src/hooks/useSelect/index.ts中getOptionLabel/getOptionValue对字符串类型使用lodash/get做路径取值对函数类型则直接调用测试 should generate options with custom optionLabel and optionValue functions 与 with nested optionLabel 分别覆盖了函数与嵌套路径两种用法。searchField指定onSearch收到输入值后按哪个字段搜索const { onSearch } useSelect({ searchField: name }); onSearch(John); // 按 name 字段搜索 John默认规则如果optionLabel是字符串则使用optionLabel的值否则回退到title字段// optionLabel 为字符串时 const { onSearch } useSelect({ optionLabel: name }); onSearch(John); // 按 name 字段搜索 // optionLabel 为函数时 const { onSearch } useSelect({ optionLabel: (item) ${item.id} - ${item.name}, }); onSearch(John); // 回退到按 title 字段搜索对应源码searchField typeof optionLabel string ? optionLabel : title测试describe(searchField)一节有专门覆盖。sorters控制选项的展示顺序会通过useList传给getList最终转换为发送给 API 的排序参数useSelect({ sorters: [ { field: title, order: asc, }, ], });交互示例见 _sort-live-preview.md其中通过按钮在asc/desc间切换动态改变排序。sorters的类型为CrudSort[]参考CrudSorting接口。filters用于过滤展示的选项同样通过useList传给getList并转换为过滤查询参数useSelect({ filters: [ { field: isActive, operator: eq, value: true, }, ], });类型为CrudFilter[]参考CrudFilters接口。注意一旦使用onSearch它会覆盖现有filters见下文。defaultValue用于从 API 额外拉取某些选项。当选项很多需要分页时defaultValue对应的记录可能不在当前可见列表中导致Select展示异常。为此useSelect会发起一个独立的useMany查询把defaultValue从后端取回并合并进选项保证它始终存在于列表。由于走的是useManydefaultValue既可以是单个值也可以是数组useSelect({ defaultValue: 1, // 或 [1, 2] });:::info 重要提醒defaultValue不会设置默认选中项它只保证默认值存在于选项中。要设置默认选中请把值传给Select的value属性或useFormconst form useForm({ defaultValues: { category: { id: 1 }, // 默认选中的值 }, }); const { selectProps } useSelect({ resource: categories, defaultValue: [1], // 确保默认值被包含在选项中 });:::演示见 _default-value-live-preview.md。源码中defaultValues统一归一化为数组useMany查询仅在defaultValues.length 0时启用测试 defaultValue、defaultValue is not an array 分别验证了数组与单值两种形态。selectedOptionsOrder配合defaultValue控制已选中选项的排序方式可选值in-place默认选中项排在底部selected-first选中项排在顶部。useSelect({ defaultValue: 1, // 或 [1, 2] selectedOptionsOrder: selected-first, // in-place | selected-first });源码中combinedOptions使用uniqBy(..., value)合并options与selectedOptions顺序由selectedOptionsOrder决定测试 should sort default data first with selectedOptionsOrder for defaultValue 验证了该逻辑。debounce对onSearch函数做防抖毫秒减少搜索时的请求频率useSelect({ resource: categories, debounce: 500, });源码默认值为300msdebounce: debounceValue 300onSearch内部使用lodash/debounce包装测试 onSearch debounce with default value (300ms)、onSearch disabled debounce (0ms) 与 should respond to onSearch prop changes without breaking the debounce interval 覆盖了默认值与边界行为。queryOptions透传给useQuery的额外选项适合覆盖重试策略等行为useSelect({ queryOptions: { retry: 3, }, });参考 useQuery 文档。需要说明的是queryOptions作用于选项列表的useList查询当没有单独传defaultValueQueryOptions时它也会被复用为defaultValue查询的选项见下文。pagination分页参数会传给getList用于构造分页查询参数包含三个子属性// 指定当前页码 useSelect({ pagination: { currentPage: 2, }, }); // 指定每页条数 useSelect({ pagination: { pageSize: 20, }, }); // 关闭分页或切换客户端/服务端分页 useSelect({ pagination: { mode: off, // off | client | server }, });mode决定是否使用服务端分页。源码中pageSize默认值为10pageSize: pagination?.pageSize ?? 10测试 should use pagination option as infinite loading when fetching list 验证了分页参数的传递。defaultValueQueryOptions当传入defaultValue时useSelect会为选中记录调用useMany该属性允许你修改这次查询的选项若未传defaultValue则使用queryOptions中的值const { options } useSelect({ resource: categories, defaultValueQueryOptions: { onSuccess: (data) { console.log(triggers when on query return on success); }, }, });源码实现defaultValueQueryOptions defaultValueQueryOptionsFromProps ?? queryOptions。onSearch 与客户端过滤onSearch允许为选项附加搜索AutoComplete 式体验若使用它会覆盖已有filtersconst { selectProps } useSelect({ resource: categories, onSearch: (value) [ { field: title, operator: contains, value, }, ], });完整演示见 _on-search-live-preview.md。测试 should use onSearch option to get filters 验证了搜索值会拼入 filters。客户端过滤如果你希望在前端过滤选项可以传入undefined的onSearch并设置filterOption为true同时可用optionFilterProp指定按label还是value过滤const { 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, }; }, //... };源码中combinedMeta getMeta({ resource, meta })会把资源定义、Hook 参数与查询参数三处的 meta 合并测试 should pass meta from resource defination, hook parameter and query parameters to dataProvider 对此有完整覆盖。更多背景见 General Concepts 的 meta 说明。dataProviderName当配置了多个dataProvider时用它指定使用哪一个适用于不同资源使用不同数据源的情况useSelect({ dataProviderName: second-data-provider, });successNotification 与 errorNotification二者分别定制数据获取成功/失败时的通知内容依赖已配置的NotificationProvider// 成功通知 useSelect({ 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实时相关属性依赖LiveProvider// liveMode: 收到实时事件后自动更新数据auto或手动更新manual useSelect({ liveMode: auto, }); // onLiveEvent: 订阅事件到达时的回调 useSelect({ onLiveEvent: (event) { console.log(event); }, }); // liveParams: 传给 liveProvider subscribe 方法的参数liveMode的详细说明可参考 Live / Realtime 文档。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。源码中该能力来自useLoadingOvertime其isLoading同时考虑了列表查询与 defaultValue 查询的isFetching测试 works correctly withintervalandonIntervalparams 验证了计时行为。返回值Return ValuesAnt Design 版useSelect的返回类型定义在 packages/antd/src/hooks/fields/useSelect/index.ts属性说明类型selectPropsAnt Design Select 的 props可直接展开Selectquery列表查询结果QueryObserverResult{ data: TData }defaultValueQuerydefaultValue 记录的查询结果QueryObserverResult{ data: TData }核心层packages/core/src/hooks/useSelect/index.ts返回的对象还包含options合并后的选项数组、onSearch防抖后的搜索函数以及overtimeAnt Design 包装层会把这些能力聚合进selectProps后透出。类型参数Type Parameters参数说明类型默认值TQueryFnData查询函数返回的数据类型继承BaseRecordBaseRecordBaseRecordTError自定义错误对象继承HttpErrorHttpErrorHttpErrorTDataselect函数返回的数据类型继承BaseRecord未指定时默认使用TQueryFnDataBaseRecordTQueryFnData常见问题FAQ如何给选项加搜索AutoComplete使用onSearch设置搜索值前端输入即触发远程搜索示例见 _on-search-live-preview.md。如何确保 defaultValue 一定出现在选项中当手头只有id时useSelect会通过useMany发起请求取回数据并标记为已选中演示见 _default-value-live-preview.md。如何修改选项的 label 和 value通过optionLabel与optionValue默认分别是title和id。例如改为name与categoryIduseSelect({ optionLabel: name, optionValue: categoryId, });可以手动创建选项吗当optionLabel/optionValue不足以表达复杂需求时可以基于query手动映射const { query } useSelect(); const options query.data?.data.map((item) ({ label: item.title, value: item.id, })); return Select options{options} /;如何与 CRUD 组件和 useForm 配合将selectProps展开到Form.Item内的Select上即可配合useForm的formProps与Create的saveButtonProps完成提交完整示例见 _crud-live-preview.mdimport { Create, useSelect, useForm } from refinedev/antd; import { Form, Select } from antd; 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 ); };完整示例基础用法示例仓库中的 examples/field-antd-use-select-basic页面代码位于 src/pages/posts包含 create/edit/list/show 完整 CRUD 场景无限加载示例field-antd-use-select-infinite见 examples/field-antd-use-select-infinite配合pagination实现滚动加载更多选项。若要在本地查看这些示例可参考对应示例目录的package.json安装依赖并启动开发服务器。小结useSelect将 Refine 的数据层能力useListuseMany Live 订阅 通知 超时检测封装成一个面向 Ant DesignSelect的即插即用接口。理解它的核心机制——selectProps聚合、optionLabel/optionValue映射、defaultValue的useMany兜底、debounce防抖搜索——能帮助你在构建管理后台时用最少的样板代码得到健壮、可搜索、可实时更新的下拉选择体验。文中所有属性行为均可对照 packages/core/src/hooks/useSelect/index.ts 与 index.spec.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),仅供参考
返回列表