You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 17:02:07