React表格中Person组件重复API请求的性能优化方案咨询
优化Person组件的重复API请求问题
问题根源
当前每个Person组件实例独立执行逻辑:当同一邮箱的多个组件同时挂载时,它们都会先检查localStorage,此时缓存还未写入(第一个请求尚未完成),因此所有实例都会发起重复的API请求,直到请求完成后才会将结果存入localStorage。
方案1:使用React Query(推荐)
React Query内置请求缓存、重复请求合并、持久化缓存等能力,可完美解决该问题。
步骤1:安装React Query
npm install @tanstack/react-query # 或 yarn add @tanstack/react-query
步骤2:配置React Query客户端(项目入口文件,如App.jsx)
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; const queryClient = new QueryClient({ defaultOptions: { queries: { cacheTime: 1000 * 60 * 60 * 24, // 缓存保留1天 staleTime: 1000 * 60 * 30, // 30分钟内数据视为新鲜,不重复请求 }, }, }); function App() { return ( <QueryClientProvider client={queryClient}> {/* 你的应用根组件 */} <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider> ); } export default App;
步骤3:重构Person组件
import { useQuery } from '@tanstack/react-query'; import { useUtils } from './path-to-useUtils'; const Person = ({ email }) => { const { callApi } = useUtils(); const { data: userProfile } = useQuery({ queryKey: ['userProfile', email], // 唯一查询标识,相同email复用缓存 queryFn: async () => { const response = await callApi({ endpoint: `WebPage/GetUserProfile?Email=${email}`, method: "GET" }); return response; }, // 从localStorage读取初始缓存 initialData: () => { const saved = localStorage.getItem(`Person:${email}`); return saved ? JSON.parse(saved) : undefined; }, // 请求成功后更新localStorage onSuccess: (data) => { localStorage.setItem(`Person:${email}`, JSON.stringify(data)); }, }); return ( <span title={userProfile?.Email || email}> {userProfile?.Name || email} </span> ); } export default Person;
核心优势:
- 相同
queryKey的查询自动共享缓存,React Query会合并同一邮箱的重复请求,同一时间仅发起一次API请求。 initialData让组件挂载时直接展示localStorage缓存数据,提升加载速度。staleTime控制数据新鲜度,避免无意义的重复请求。
方案2:自定义全局缓存管理器(无第三方依赖)
若不想引入第三方库,可通过全局缓存工具统一处理请求与缓存,避免重复请求。
步骤1:创建全局缓存工具
// utils/userCache.js const memoryCache = new Map(); const pendingRequests = new Map(); export async function getUserProfile(email, callApi) { // 优先读取内存缓存 if (memoryCache.has(email)) { return memoryCache.get(email); } // 复用正在进行的请求Promise if (pendingRequests.has(email)) { return pendingRequests.get(email); } // 读取localStorage缓存 const saved = localStorage.getItem(`Person:${email}`); if (saved) { const data = JSON.parse(saved); memoryCache.set(email, data); return data; } // 发起新请求并跟踪状态 const requestPromise = callApi({ endpoint: `WebPage/GetUserProfile?Email=${email}`, method: "GET" }).then((data) => { memoryCache.set(email, data); localStorage.setItem(`Person:${email}`, JSON.stringify(data)); pendingRequests.delete(email); return data; }).catch((err) => { pendingRequests.delete(email); throw err; }); pendingRequests.set(email, requestPromise); return requestPromise; }
步骤2:重构Person组件
import { useState, useEffect } from 'react'; import { useUtils } from './path-to-useUtils'; import { getUserProfile } from './utils/userCache'; const Person = ({ email }) => { const [userProfile, setUserProfile] = useState(); const { callApi } = useUtils(); useEffect(() => { getUserProfile(email, callApi).then(setUserProfile); }, [email, callApi]); return ( <span title={userProfile?.Email || email}> {userProfile?.Name || email} </span> ); } export default Person;
核心优势:
- 用
memoryCache减少localStorage读取次数,pendingRequests避免同一邮箱的重复请求。 - 保留localStorage的持久化缓存能力,无需依赖第三方库。
内容的提问来源于stack exchange,提问作者qwer11121
相关产品推荐
相关产品推荐

