ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

refine v3 + Ant Design:使用 useSimpleList 与 onSearch 构建可搜索的产品列表

refine v3 + Ant Design:使用 useSimpleList 与 onSearch 构建可搜索的产品列表 refine v3 Ant Design使用 useSimpleList 与 onSearch 构建可搜索的产品列表【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refineuseSimpleList是 refine 的 Ant Design 集成中专门面向List组件封装的列表 Hook它开箱即用地提供了分页、排序、过滤与搜索能力底层复用核心包的useTable完成数据获取。本文以官方 live preview 示例产品列表按名称与描述搜索为骨架结合packages/antd源码与测试用例完整讲解useSimpleList的属性、返回值以及如何用onSearchsearchFormProps打造多字段搜索表单。一、从一个可运行的搜索列表示例开始在 refine 的版本化文档中搜索能力以一段可实时预览的代码呈现见 search-live-preview.md。它展示了一个非常典型的场景页面顶部是一个内联搜索表单按name与description模糊匹配下方是 Ant Design 的List组件渲染产品数据。完整示例代码如下setInitialRoutes([/products]); import { Typography, AntdList, useSimpleList, Form, Input, Button, } from pankod/refine-antd; import { HttpError } from pankod/refine-core; const { Text } Typography; interface IProduct { id: number; name: string; description: string; price: string; } interface ISearch { name: string; description: string; } const ProductList: React.FC () { const { listProps, searchFormProps } useSimpleList IProduct, HttpError, ISearch ({ onSearch: (values) { return [ { field: name, operator: contains, value: values.name, }, { field: description, operator: contains, value: values.description, }, ]; }, }); return ( div Form {...searchFormProps} layoutinline Form.Item namename Input placeholderSearch by name / /Form.Item Form.Item namedescription Input placeholderSearch by description / /Form.Item Button typeprimary onClick{searchFormProps.form?.submit} Search /Button /Form AntdList {...listProps} renderItem{renderItem} / /div ); }; const renderItem (item: IProduct) { const { id, name, description, price } item; return ( AntdList.Item actions{[Text key{id}{price}/Text]} AntdList.Item.Meta title{name} description{description} / /AntdList.Item ); };代码中的关键点useSimpleListIProduct, HttpError, ISearch的第三个泛型参数ISearch声明了表单值的类型onSearch接收表单提交的值values返回一组CrudFilters这里是两个contains条件的数组searchFormProps直接展开到Form上表单提交时会自动触发onSearchlistProps直接展开到AntdList上数据源、加载状态与分页配置都已内置。这个示例在文档中被SearchLivePreview /引用嵌入在 useSimpleList.md 的 Search 章节中与 Basic Usage、Sorting、Filtering 等示例并列。二、底层原理onSearch 是如何驱动列表重新取数的useSimpleList的实现位于 packages/antd/src/hooks/useSimpleList/useSimpleList.ts。从源码看它并非独立实现一套取数逻辑而是把核心包useTable的全部能力分页、排序、过滤、实时订阅转发给 Ant Design 的List组件。1. onSearch 的类型与契约export type useSimpleListPropsTQueryFnData, TError, TSearchVariables, TData useTablePropsCoreTQueryFnData, TError, TData { onSearch?: (data: TSearchVariables) CrudFilters | PromiseCrudFilters; };onSearch是一个可选函数输入是表单的值即TSearchVariables输出是CrudFilters或返回CrudFilters的 Promise——这意味着你可以在搜索前做异步校验或预处理。2. onFinish 的内部调用链在useSimpleList内部返回值searchFormProps实际是searchFormProps: { form, onFinish, }其中form是Form.useFormTSearchVariables()创建的表单实例onFinish的完整逻辑如下摘录自源码const onFinish async (values: TSearchVariables) { if (onSearch) { const searchFilters await onSearch(values); if (isPaginationEnabled) { setCurrentPage?.(1); } return setFilters(searchFilters); } };这里揭示了三条重要行为表单提交 → 调用onSearch(values)得到过滤条件搜索成功后当前页会被重置为第 1 页setCurrentPage(1)保证搜索结果从第一页开始展示过滤条件通过setFilters写入状态而useTable内部的状态变更会触发新的数据请求。3. listProps 的构成listProps返回三个与List兼容的关键字段listProps: { dataSource: data?.data, // 接口返回的记录数组 loading: liveMode auto ? isLoading : !isFetched, // 加载状态 pagination: antdPagination(), // 分页配置 }其中loading有一个细节当liveMode为auto时直接使用isLoading否则使用!isFetched。pagination由antdPagination()生成内部通过createLinkForSyncWithLocation为每一页生成真实链接而非依赖 React 状态当分页被关闭时返回false。4. 数据请求链按文档说明Under the hood it usesuseTablefor the fetch而核心包useTable又基于useList完成数据获取参见 core useTable 文档 与 useList 文档。因此整条调用链是Antd Form 提交 → searchFormProps.onFinish(values) → onSearch(values) 产出 CrudFilters → setFilters(searchFilters) 且 currentPage 归位 1 → core useTable 状态更新 → useList 发起 dataProvider.getList 请求 → listProps.dataSource 更新 → AntdList 重新渲染三、搜索表单深入searchFormProps 的完整用法searchFormProps本质上就是 Ant Design 的Form实例属性。文档中它的定义是当searchFormProps.onFinish被调用时会触发onSearch函数你也可以用searchFormProps.form.submit手动提交表单。因此有两种常见的触发搜索的方式方式一依赖 Form 的提交事件示例中的做法Form {...searchFormProps} layoutinline Form.Item namename Input placeholderSearch by name / /Form.Item Form.Item namedescription Input placeholderSearch by description / /Form.Item Button typeprimary htmlTypesubmitSearch/Button /Form方式二用 Button 显式调用表单的 submitButton typeprimary onClick{searchFormProps.form?.submit} Search /Button两种方式最终都会走到同一个onFinish随后进入onSearch→setFilters的流程。onSearch适合需要多字段组合过滤的场景如果只是单字段即时过滤可以直接使用setFilters见下文 Filtering 部分例如Input.Search的onChange事件。四、属性详解从 resource 到 liveParamsuseSimpleList接受与核心useTable一致的一组配置属性类型定义可对照 packages/core/src/hooks/useTable/index.ts 中的useTableProps以下逐一说明。resourceresource会作为参数传给dataProvider通常用作 API 端点路径具体如何映射取决于 dataProvider 的实现参见>const { listProps: productsListProps } useSimpleListIProduct, HttpError(); const { listProps: categoriesListProps } useSimpleListICategory, HttpError({ resource: categories, });还可以传入带路径的 URL 片段useSimpleList({ resource: categories/subcategory, // BASE_URL_FROM_DATA_PROVIDER/categories/subcategory });initialCurrent 与 initialPageSizeinitialCurrent默认1设置初始页码initialPageSize默认10设置每页条数。useSimpleList({ initialCurrent: 2, // 初始展示第 2 页 initialPageSize: 20, // 每页 20 条 });initialSorter 与 permanentSorter两者都用于设置排序区别在于是否可被用户操作清除initialSorter临时排序用户改变排序后会被清除permanentSorter永久排序不可变更始终与当前排序合并生效。useSimpleList({ initialSorter: [{ field: name, order: asc }], permanentSorter: [{ field: id, order: desc }], });排序类型为CrudSorting字段 顺序相关接口可参考 core interfaces 文档。排序功能同样有一个 live 示例见 sorting-live-preview.md按name降序展示。initialFilter 与 permanentFilter过滤规则与排序类似initialFilter可被清除、permanentFilter永久生效类型为CrudFiltersuseSimpleList({ initialFilter: [{ field: name, operator: contains, value: Foo }], permanentFilter: [{ field: status, operator: eq, value: published }], });过滤示例见 filtering-live-preview.md其中通过setFilters配合Input.Search实现即时搜索。defaultSetFilterBehavior默认merge用于控制setFilters时新旧过滤条件如何合并merge新过滤条件与旧条件合并同名字段替换不同字段追加replace直接用新过滤条件替换全部旧条件。useSimpleList({ defaultSetFilterBehavior: replace, });也可以在调用setFilters时通过第二个参数按次覆盖setFilters(newFilters, replace);hasPagination决定是否使用服务端分页。文档默认值为false注意Ant Design 集成版中该语义与核心useTable的pagination配置对应。关闭后List将不显示分页元素可在客户端自行处理分页useSimpleList({ hasPagination: false, });syncWithLocation默认false。开启后分页、排序、过滤状态会自动编码进 URL 的查询参数URL 变化时列表状态也会自动同步从而支持收藏、分享和跨路由复现列表视图。该值也可以在Refine组件上全局设置。useSimpleList({ syncWithLocation: true, });queryOptionsuseSimpleList的数据请求最终由 React Query 驱动可透传queryOptions如retry、staleTime等useSimpleList({ queryOptions: { retry: 3, }, });metaDatametaData有两个用途向 dataProvider 方法传递附加信息或者用纯 JS 对象JSON生成 GraphQL 查询。典型用法是传递自定义请求头useSimpleList({ metaData: { headers: { x-meta-data: true }, }, });dataProvider 的getList中可以这样消费const myDataProvider { getList: async ({ resource, pagination, hasPagination, sort, filters, metaData }) { const headers metaData?.headers ?? {}; const url ${apiUrl}/${resource}; const { data } await httpClient.get(url, { headers }); return { data }; }, };dataProviderName当项目配置了多个 dataProvider 时用该属性指定使用哪一个useSimpleList({ dataProviderName: second-data-provider, });successNotification 与 errorNotification依赖NotificationProvider参见 notification-provider 文档。取数成功或失败后可用这两个回调自定义通知内容useSimpleList({ successNotification: (data, values, resource) ({ message: ${data.title} Successfully fetched., description: Success with no errors, type: success, }), errorNotification: (data, values, resource) ({ message: Something went wrong when getting ${data.id}, description: Error, type: error, }), });liveMode、onLiveEvent 与 liveParams这三个属性用于实时更新场景依赖LiveProvider参见 live-provider 文档liveMode收到实时事件后是否自动更新数据auto自动、manual手动onLiveEvent订阅到新事件时的回调liveParams传给liveProvider.subscribe方法的额外参数。useSimpleList({ liveMode: auto, onLiveEvent: (event) { console.log(event); }, });当useSimpleList挂载时它会调用liveProvider的subscribe方法并携带channel、resource等参数以便订阅该资源的实时变更。onSearch再次强调其完整语义上文已有示例当searchFormProps.onFinish被调用时onSearch收到表单值并返回CrudFilters | PromiseCrudFilters同时当前页会被重置为 1。它特别适合用Form做多字段组合过滤。五、返回值详解useSimpleList的返回值类型定义见 useSimpleList.ts 中的useSimpleListReturnType包括返回值说明listProps兼容 Ant DesignList的 props包含dataSource、loading、paginationsearchFormPropsAnt DesignForm实例属性formonFinish用于构建搜索表单query底层useTable的tableQueryQueryObserverResult可访问isSuccess等状态filters/setFilters当前过滤状态与更新函数sorters/setSorters当前排序状态与更新函数currentPage/setCurrentPage当前页码与更新函数pageSize/setPageSize每页条数与更新函数pageCount总页数createLinkForSyncWithLocation生成与 URL 同步的链接overtime加载超时状态来自useLoadingOvertimeresult取数结果其中setFilters的类型签名是((filters: CrudFilters, behavior?: SetFilterBehavior) void) ((setter: (prevFilters: CrudFilters) CrudFilters) void)即既可以直接传入新的过滤数组也可以传入一个基于旧状态计算的函数。listProps.pagination返回pageSize、current、position等分页配置。如果你想微调分页展示例如把分页放到顶部并缩小尺寸可以展开后覆盖const { listProps } useSimpleListIProduct(); return ( AntdList {...listProps} renderItem{renderItem} pagination{{ ...listProps.pagination, position: top, size: small, }} / );六、测试用例如何验证这些行为仓库中的单元测试 useSimpleList.spec.ts 使用MockJSONServer与TestWrapper对 Hook 行为做了完整验证可以从侧面印证上文所述的实现事实默认行为断言dataSource长度为 2、pagination包含pageSize: 10、current: 1、total: 2且simple: true小屏简化为简单分页初始分页参数传入pagination: { pageSize: 1, currentPage: 2 }后断言分页对象包含pageSize: 1与current: 2禁用分页pagination: { mode: off }时断言pagination为false自定义资源resource: categories时能够从对应资源取数分页模式client与server两种模式都会设置分页 propsquery 返回值断言query.isSuccess为真且query与queryResult一致。七、结合其他能力分页、排序、过滤与搜索协同useSimpleList的全部能力围绕同一个CrudFilters/CrudSorting/ 分页状态模型运转因此可以自由组合搜索 分页搜索提交后自动回到第 1 页由onFinish中的setCurrentPage?.(1)保证排序 过滤initialSorter、initialFilter与permanentSorter、permanentFilter分别提供初始与永久两种语义满足默认视图与业务硬约束URL 状态同步开启syncWithLocation后以上所有状态均可被编码进 URL实现可分享的列表视图实时更新配合LiveProviderlistProps.loading在liveMode auto时直接跟踪isLoading保证实时刷新过程中的加载反馈。基础用法、排序、过滤与搜索四个 live 示例在文档中并列为 useSimpleList.md 的核心章节对应 basic-usage-live-preview.md、sorting-live-preview.md、filtering-live-preview.md 与 search-live-preview.md可作为完整的参考实现按需取用。八、小结useSimpleList是 refine v3 中连接核心取数能力与 Ant DesignList的桥梁内部基于核心useTable无需关心请求细节多字段搜索的标准范式是onSearchsearchFormProps表单提交 →onSearch产出CrudFilters→ 页码归 1 →setFilters触发重新取数分页、排序、过滤、搜索、实时更新、URL 状态同步等能力均可组合使用属性与返回值的完整语义以 useSimpleList.ts 源码与 useSimpleList.spec.ts 测试为准若需在列表页展示分类等其他资源可通过resource属性覆盖默认路由推断配合dataProviderName还能在多数据源项目中灵活切换。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表