自定义Hook useUserData重复触发重渲染,如何在Hook内实现数据缓存?
解决方案
方案1:利用GQL客户端原生缓存(最优选择)
你使用的useCustomQuery作为GraphQL客户端自带的查询Hook,本身就内置了成熟的缓存能力,不需要额外手写缓存逻辑,只需要调整查询策略即可:
export const useUserData = () => { const { data, isLoading, error } = useCustomQuery({ query: async (query) => { return getFields(query.me, 'account_id', 'role', 'email', 'profile_image'); }, // 新增缓存策略配置:优先读取本地缓存,缓存不存在才发起网络请求 fetchPolicy: 'cache-first', // 可选配置:缓存有效时间(单位ms),超过时间自动重新拉取最新数据 staleTime: 10 * 60 * 1000 // 示例:缓存10分钟有效 }); return { isLoading, error, me: data }; };
如果你的客户端配置项命名不同,比如部分客户端将该参数命名为policy,对应调整即可,原生缓存会自动处理缓存更新、失效、重复请求去重等场景,维护成本最低。
方案2:通过Context实现全局数据共享(无侵入适配)
如果你的GQL客户端不支持全局缓存配置,或者需要完全自主控制缓存逻辑,可以用Context封装全局状态,保证全应用只发起一次请求:
- 首先封装全局用户数据Provider
import { createContext, useContext } from 'react'; const UserDataContext = createContext({ isLoading: true, error: null, me: null, refetch: () => {} }); export const UserDataProvider = ({ children }) => { // 仅在Provider初始化时调用一次查询,所有子组件复用该结果 const { data, isLoading, error, refetch } = useCustomQuery({ query: async (query) => { return getFields(query.me, 'account_id', 'role', 'email', 'profile_image'); }, }); return ( <UserDataContext.Provider value={{ isLoading, error, me: data, refetch }}> {children} </UserDataContext.Provider> ) } // 原有自定义Hook改造为从Context取数据,接口完全兼容 export const useUserData = () => { return useContext(UserDataContext); };
- 在应用根组件包裹Provider
// App.jsx 入口文件 import { UserDataProvider } from './useUserData'; function App() { return ( <UserDataProvider> {/* 原有应用组件 */} </UserDataProvider> ) }
改造后所有组件调用useUserData都会复用同一份查询结果,不会重复发起请求,还支持调用返回的refetch方法手动刷新用户数据,全应用自动同步。
可选优化
如果需要实现缓存自动失效,可以在缓存逻辑中加入过期时间判断,超过设定阈值后自动触发重新拉取,保证数据不会过旧。
内容的提问来源于stack exchange,提问作者ambe5960
相关产品推荐
相关产品推荐

