十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Refine v5 useLogList Hook 实战指南:审计日志列表查询、底层原理与边界情况

Refine v5 useLogList Hook 实战指南:审计日志列表查询、底层原理与边界情况 Refine v5 useLogList Hook 实战指南审计日志列表查询、底层原理与边界情况【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine导读useLogList是 Refine 提供的审计日志Audit Log查询 Hook用于在应用中获取并筛选审计事件列表其底层封装了auditLogProvider的get方法。本文以 useLogList 官方文档 为主体结合 refinedev/core 源码 与单元测试深入讲解其调用链、query key 生成规则、参数/返回值语义以及queryOptions的覆盖行为帮助你为合规审计、操作追溯等场景快速搭建可靠的日志列表。一、useLogList 是什么当你的应用需要展示某个资源发生过哪些操作、由谁执行这类审计事件时就可以使用useLogList。它在内部调用auditLogProvider.get方法拉取事件列表并复用tanstack/react-query的useQuery提供缓存、重试、状态管理等能力。Refine 的审计日志体系由 auditLogProvider 统一承载它包含三个方法create记录一条审计事件get返回事件列表update更新一条审计事件。useLogList只负责与get对接useLog则负责与create/update对接。两者相辅相成写操作走useLog或自动化的数据变更 Hook读操作走useLogList。二、快速上手最基本的用法只需传入resourceimport { useLogList } from refinedev/core; const postAuditLogResults useLogList({ resource: posts, });其中postAuditLogResults就是useQuery的返回结果你可以像使用普通 react-query 查询一样访问data、isLoading、isFetched、error、refetch等字段const { data, isLoading, error, refetch } useLogList({ resource: posts, }); if (isLoading) return div加载审计日志中.../div; if (error) return div加载失败{error.message}/div; return ( ul {data?.map((event: any) ( li key{event.id} [{event.action}] {JSON.stringify(event.data)} /li ))} /ul );需要说明的是useLogList必须在使用前将auditLogProvider传入Refine组件否则get方法不存在查询会被禁用详见下文enabled 默认行为一节。三、底层实现一次查询的完整调用链阅读 useLogList 源码 可以看到它的完整逻辑export const useLogList TQueryFnData any, TError extends HttpError HttpError, TData TQueryFnData, ({ resource, action, meta, author, queryOptions, }: UseLogPropsTQueryFnData, TError, TData): UseQueryResultTData, TError { const { get } useContext(AuditLogContext); const { keys } useKeys(); const queryResponse useQueryTQueryFnData, TError, TData({ queryKey: keys() .audit() .resource(resource) .action(list) .params(meta) .get(), queryFn: () get?.({ resource, action, author, meta, }) ?? Promise.resolve([]), enabled: typeof get ! undefined, ...queryOptions, retry: false, meta: { ...queryOptions?.meta, ...getXRay(useLogList, resource), }, }); return queryResponse; };整个调用链可以拆解为四个关键环节1. 从 AuditLogContext 取出getuseLogList通过useContext(AuditLogContext)获取auditLogProvider暴露的get方法而不是直接读取props。这意味着auditLogProvider是通过Refine auditLogProvider{...}以全局上下文的方式注入的任何层级的组件都能直接调用useLogList无需层层透传。2. 自动生成稳定且可缓存的 query key查询键通过useKeys()构建keys().audit().resource(resource).action(list).params(meta).get()它固定了action为字符串list注意这里的list是查询动作标识不是审计事件类型并把resource与meta纳入 key 的组成。这意味着相同resource 相同meta的查询会命中同一份缓存切页或重复渲染时直接复用当meta中的筛选条件如记录 id变化时key 随之变化react-query 会自动发起新查询。具体的 key 生成实现位于 keys helper 的audit()方法中。3. 调用get并处理未配置 provider的兜底queryFn中使用了可选调用get?.(...)当auditLogProvider未配置时get为undefined此时返回Promise.resolve([])空数组不会抛出异常。与此同时enabled: typeof get ! undefined会在 provider 缺失时自动禁用查询避免无意义的请求。也就是说即使忘记配置 provider组件也不会崩溃只是拿不到数据。4. 注入 DevTools 追踪信息最终传给useQuery的meta会被合并进getXRay(useLogList, resource)生成的追踪信息供 Refine DevTools 的 X-Ray 面板展示 Hook 调用关系与资源名称便于调试。四、参数详解PropertiesuseLogList接受以下属性与源码中的 UseLogProps 类型一一对应Property类型默认值说明resource必填string从路由读取的 action要查询审计日志的资源名称例如posts、productsactionstring—按操作类型筛选例如create、update、deleteauthorRecordstring, any—按操作者筛选例如{ id: 1 }、{ username: admin }metaRecordstring, any—附加元数据通常用于携带记录 id 等筛选条件queryOptionsUseQueryOptionsTQueryFnData, TError, TData—透传给useQuery的选项可覆盖 queryKey、queryFn 等各参数的实战含义resource必填项决定查询哪一类资源的审计事件。虽然表格中默认值为从路由读取的 action但源码将其声明为必填建议始终显式传入。action用于只筛选某一种操作例如仅查看删除记录。若省略则由auditLogProvider.get自行决定返回范围。meta最常见的用法是携带id查询某一条记录的全部审计历史。例如{ id: 1 }。源码会把meta原样传给get同时它也会参与 query key 的生成。author用于按操作者过滤例如展示某个管理员执行过的所有操作。queryOptionsreact-query 的完整选项集合覆盖场景见下文第六节。五、泛型参数与返回值Type Parameters参数描述类型默认值TQueryFnData查询函数返回的数据类型继承自BaseRecordBaseRecordBaseRecordTError自定义错误类型继承自HttpErrorHttpErrorHttpErrorTDataselect函数返回的数据类型继承自BaseRecord未指定时取TQueryFnDataBaseRecordTQueryFnData使用示例import type { HttpError } from refinedev/core; type PostAuditEvent { id: number; action: string; data: Recordstring, any; author?: { name?: string }; }; const { data } useLogListPostAuditEvent[], HttpError({ resource: posts, });Return values描述类型react-query的useQuery返回结果UseQueryResult{ data: TData; }返回值包含data、isLoading、isError、error、isFetched、refetch、isFetching等标准字段其中data是get方法 resolve 出的审计事件数组。注意源码中返回类型实际为UseQueryResultTData, TErrorTData即整个查询数据与文档表格中标注的{ data: TData }相对应的是 react-query 内部对结果对象的包裹语义。六、通过 queryOptions 精确控制查询行为queryOptions会被展开合并进useQuery实现细粒度控制。结合单元测试可以确认以下两种核心覆盖行为。覆盖 queryKey默认 query key 由keys().audit()...自动生成如果你需要手动指定例如与应用其他查询共享缓存可以直接传入useLogList({ resource: posts, queryOptions: { queryKey: [foo, bar], }, });对应的测试用例should override queryKey with queryOptions.queryKey验证了传入后缓存查询键被替换为[foo, bar]。覆盖 queryFn默认的queryFn调用get方法当你希望完全接管数据获取逻辑例如先从本地缓存读取、失败再请求接口时useLogList({ resource: posts, queryOptions: { queryFn: async () { // 自定义获取逻辑 return customFetchAuditLogs(); }, }, });测试用例should override queryFn with queryOptions.queryFn验证了覆盖后get方法不会被调用且自定义queryFn正常执行。此外还有两个源码层面的固定行为需要留意retry: false即使你通过queryOptions传入retry也会被展开顺序中靠后的retry: false覆盖。也就是说 useLogList 的查询默认不重试请求失败立即进入error状态。这是有意的设计——审计查询失败通常需要立刻暴露给用户而不是静默重试。meta合并你传入的queryOptions.meta会与 DevTools 的getXRay追踪信息合并两者不会互相覆盖。七、完整实战auditLogProvider.get useLogList要让useLogList真正返回数据先按审计日志 Provider 文档实现get方法。例如按资源名与记录 id 查询事件import type { AuditLogProvider } from refinedev/core; export const auditLogProvider: AuditLogProvider { get: async (params) { const { resource, meta, action, author } params; const response await fetch( https://example.com/api/audit-logs/${resource}/${meta?.id}, { method: GET, }, ); const data await response.json(); return data; }, // create / update 按需实现 };再通过Refine注入import { Refine } from refinedev/core; import { auditLogProvider } from ./audit-log-provider; const App () ( Refine /* ... */ auditLogProvider{auditLogProvider} / );然后在任意页面组件中查询某篇文章id1的全部操作记录import { useLogList } from refinedev/core; export const PostAuditLog ({ postId }: { postId: number }) { const { data, isLoading, isError, error } useLogList({ resource: posts, meta: { id: postId }, // 查询该记录的全部审计事件 }); if (isLoading) return p加载中.../p; if (isError) return p出错了{error?.message}/p; return ( table thead tr th事件类型/th th操作者/th th变更内容/th /tr /thead tbody {data?.map((log: any) ( tr key{log.id} td{log.action}/td td{log.author?.name ?? -}/td td pre{JSON.stringify(log.data ?? log.previousData, null, 2)}/pre /td /tr ))} /tbody /table ); };当postId变化时meta改变会生成新的 query key自动触发重新查询——这正是审计日志按记录查看历史场景的标准做法。组合筛选action author如果需要只看某个管理员对某篇文章的删除操作可以同时传入多个筛选条件const { data } useLogList({ resource: posts, action: delete, author: { username: admin }, meta: { id: postId }, });筛选的最终解释权在auditLogProvider.get的实现中Refine 只负责把action、author、meta原样透传源码证据服务端如何组合这些条件取决于你的后端 API。八、测试验证源码如何保障行为正确仓库为useLogList提供了专门的单元测试 useLogList/index.spec.ts覆盖了三条核心行为透传属性useLogList({ resource: posts, action: list, meta: { id: 1 } })会以相同参数调用auditLogProvider.get且返回的data与get的 resolve 值严格一致queryKey 覆盖传入queryOptions.queryKey后react-query 缓存中只存在自定义 keyqueryFn 覆盖传入queryOptions.queryFn后get不再被调用改由自定义函数取数。这些测试同时验证了useLogList与 react-query 的集成行为是你在二次封装或排查为什么没触发请求问题时的重要参考。九、使用建议与边界情况总结provider 未配置时查询自动禁用enabled: falsedata保持undefined不会报错请检查Refine是否传入了auditLogProvider。不要依赖重试retry: false是写死的失败即失败请在前端做好错误提示与手动refetch。查询键的语义默认 key 中的action(list)表示列表查询这一动作与审计事件类型create/update/delete无关两者不要混淆。与 useLog 的分工写审计事件用useLog底层调create/update读审计事件用useLogList底层调get。Refine 的数据变更 Hook如useCreate、useUpdate、useDelete等在成功后会自动调用create记录事件无需你手动埋点。按变更类型裁剪日志如果只想记录部分操作可在资源配置中使用meta.audit白名单例如meta: { audit: [create] }表示只有create事件会被记录详见 audit-log-provider 文档。安全边界官方文档明确建议审计日志在服务端创建因为客户端写入的数据可被篡改不能作为可信的事实来源。get查询侧的筛选参数也应视为用户输入在后端做好权限校验。结语useLogList是 Refine 审计日志体系中的读取入口它把auditLogProvider.get包装成声明式的 react-query 查询自动处理缓存键、provider 缺失兜底与 DevTools 追踪。掌握它的参数语义、query key 生成规则和queryOptions覆盖行为你就可以在合规审计、操作追溯等场景中快速构建出健壮、可缓存的日志列表并与 Refine 的数据变更 Hook 形成完整的自动记录 便捷查询闭环。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表