refine useResourceWithRoute 钩子:按路由名获取资源定义,及其在 v4 中的现代替代方案 useResource
【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine
本篇以 refine(v3 版本 API 参考)中的useResourceWithRoute钩子为核心,讲清它的设计定位——从<Refine>组件的resources数组中按路由名反查资源对象、其返回值类型与典型用法,并结合当前仓库源码说明该钩子为何被标记为 deprecated,以及在新路由体系下应如何使用useResource与useResourceParams完成同样的资源解析。读完后,你将能在旧项目中正确使用该钩子,并掌握在新项目中获取资源定义、路由参数与 action 的推荐方式。
useResourceWithRoute 是什么
useResourceWithRoute用于按路由名(route name)获取resources数组中定义的资源对象。这些resources是开发者在<Refine>组件上声明的资源列表,每个资源项包含name、route、list/create/edit/show等路由与页面配置。
根据 v3 API 参考文档 的明确说明,这个钩子有两个关键定位:
- 它是 refine内部使用的钩子(used internal in refine),正常情况下业务代码不需要直接调用;
- 官方仍将其导出,是因为部分使用场景下它会很有用(we export it as it may be useful for some use-cases)。
也就是说,它是一个"半内部"工具:你在自定义路由组件、自绘菜单或需要"当前 URL 对应哪个资源"这类逻辑时,可以借助它拿到资源定义;但日常 CRUD 开发中,绝大多数场景不需要触碰它。
用法示例
文档给出的标准用法如下(摘自 useResourceWithRoute.md):
import { useResourceWithRoute } from "@pankod/refine-core"; const resourceWithRoute = useResourceWithRoute(); const resource = resourceWithRoute("posts");要点解析:
useResourceWithRoute()本身不接收参数,调用后返回一个函数resourceWithRoute;- 向该函数传入路由名(如
"posts"),它会到<Refine>声明的resources数组中匹配出对应的资源对象并返回; - 返回的资源对象类型是
IResourceItem,即你在resources数组中定义的那个资源项(含name、route、label、各 action 组件配置等)。
API Reference 与返回值
原始文档的 API 部分很简洁,其返回值定义如下:
| 描述 | 类型 |
|---|---|
resourceWithRoute | (route: string) => IResourceItem |
即钩子返回一个函数,入参为字符串类型的路由名,出参为IResourceItem资源对象。
要理解这个返回值的实际内容,需要看IResourceItem的构成。v3 文档中 useResource 参考页 给出了该接口的完整形态:
interface IResourceItem extends IResourceComponents { name: string; // 资源名,也是传给 dataProvider 的 resource 参数 label?: string; // 用于菜单、面包屑等展示 route?: string; // 路由名,useResourceWithRoute 就是按它匹配的 icon?: ReactNode; canCreate?: boolean; canEdit?: boolean; canShow?: boolean; canDelete?: boolean; options?: OptionsProps; parentName?: string; // 嵌套资源时指向父资源 }其中IResourceComponents声明了list、create、edit、show四个可选页面组件。文档还特别指出:canCreate、canShow、canEdit等布尔属性会在对应组件定义于resources时自动生成,即你配了edit组件,canEdit即为true。
从接口结构可以推断,useResourceWithRoute的工作流程是:以传入的 route 字符串为 key,在resources数组中查找route(或name)相等的项,返回整个资源对象——这正是"按路由名反查资源"语义的来源。
同族钩子 useResource(v3 版本)
与useResourceWithRoute同属 v3 资源类钩子的是useResource,两者关系需要分清:
useResource返回resources数组本身,以及从当前路由和 query 参数推断出的resource、resourceName、id、action;- 它也支持通过
resourceNameOrRouteName属性按名称取资源:
import { useResource } from "@pankod/refine-core"; const { resource } = useResource({ resourceNameOrRouteName: "posts", });- 而
useResourceWithRoute只暴露"route → 资源对象"这一个函数式能力,定位更窄。
v3 文档中useResource的返回值包括:
| 字段 | 含义 |
|---|---|
resources | 在<Refine>中定义的IResourceItem[] |
resource | 当前资源对象 |
resourceName | 资源名 |
id | query 参数id |
action | query 参数action(create|edit|show|clone|undefined) |
现状:已废弃,仅限旧路由体系
需要注意一个关键事实:useResourceWithRoute在当前版本(v4 及以上)中已被废弃。仓库的 packages/core/CHANGELOG.md 在描述新路由体系的迁移说明中明确写道:
useResourceWithRouteis now deprecated and only works with the legacy routing system.
即:该钩子只与旧版(legacy)路由系统兼容。如果你维护的是 v3 老项目、仍在使用 legacy 路由,可以继续沿用文档中的用法;但如果新项目或已完成 v4 迁移,应改用新的资源类钩子。
v4 替代实现:useResource 的当前源码
当前仓库中useResource的真实实现位于 packages/core/src/hooks/use-resource-params/use-resource/index.ts,它替代了useResourceWithRoute的"按名称/路由取资源"职责,能力更强:
export function useResource(args?: UseResourceParam): UseResourceReturnType { const { resources } = useContext(ResourceContext); const params = useParsed(); const select = (resourceName: string, force = true) => { const pickedResource = pickResource(resourceName, resources); if (pickedResource) { return { resource: pickedResource, identifier: pickedResource.identifier ?? pickedResource.name, }; } if (force) { // 未找到时创建临时资源项,保证调用方总能拿到对象 const resource = { name: resourceName, identifier: resourceName }; return { resource, identifier: resource.name }; } return undefined; }; // ... }从源码(见 index.ts 第 56–113 行)可以确认几个关键行为:
- 参数语义:
useResource(identifier?)接受一个可选的资源标识(identifier 或 name)。传入时优先从resources中匹配;未传入时则回退到从当前路由解析出的资源(useParsed()的params.resource)。这覆盖了useResourceWithRoute的"按路由名查资源"场景。 - 容错创建:当传入的 name 在
resources中不存在且force为true(默认)时,源码会现场构造一个{ name, identifier }的临时资源对象返回,而不是抛错——这对"操作一个未在resources中声明的临时资源"的场景很实用。 - 返回值:
{ resources, resource, select, identifier },其中select(resourceName, force)就是文档化过的"按名称选资源"函数,identifier则统一处理了资源未显式声明identifier时回退到name的逻辑。
资源类型定义现在位于 packages/core/src/contexts/resource/types.ts。与 v3 相比,IResourceComponents的四个 action(list/create/clone/edit/show)在 v4 中表示路由路径(ResourceRoutePath),而label、hide、icon、parent、dataProviderName等配置收敛到了meta中,并新增了identifier字段用于避免资源名冲突(见 types.ts 第 68–92 行)。
更底层的组合:useResourceParams
如果你的需求不只是"拿到资源对象",而是要同时推断id与action,v4 提供了组合钩子useResourceParams。它的文档注释(见 index.ts 第 32–53 行)完整描述了推断规则:
resource:显式传入优先(即使未在<Refine/>中声明),否则从路由推断;id:显式传入优先,否则从路由推断;若自定义 resource 与路由推断的不同,则id取undefined;action:显式传入优先,否则从路由推断;formAction:仅能取edit/clone/create,resource 不一致时回退为create。
其内部正是基于useResource()的select与identifier完成"显式参数 vs 路由推断"的仲裁(见 index.ts 第 54–103 行)。相关行为有对应测试覆盖,可参考 index.spec.tsx。
选型建议
| 场景 | 推荐方案 |
|---|---|
| v3 老项目、legacy 路由,需要按路由名反查资源 | useResourceWithRoute(按 v3 文档用法,见本文"用法示例") |
| v4+ 新项目,按名称/路由获取资源对象 | useResource()/useResource("posts"),需要按名查找时用返回的select |
| v4+ 需要同时推断 resource / id / action / formAction | useResourceParams({ resource?, id?, action? }) |
适用前提与限制:useResourceWithRoute的用法仅在 v3 及 legacy 路由体系下有效,官方 CHANGELOG 已明确其 deprecated 状态;在新路由体系下,useParsed、useResource等钩子接管了"路由 → 资源"的解析职责。如果你在 v4 代码中搜索useResourceWithRoute找不到导出,这是符合预期的——它的职责已被上文介绍的useResource完整承接。
参考文件
- useResourceWithRoute 文档(v3)
- useResource 文档(v3)
- useResource 当前实现
- useResourceParams 实现
- 资源类型定义
- 废弃声明所在 CHANGELOG
【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考