当前位置: 首页 > 知识库问答 >
问题:

react.js - 如何管理多个React组件的异步请求?

百里骏
2023-12-14

React中组件A里有个获取配置数据的异步请求,列表中多个组件A就会触发多个相同的异步请求,期望是等到第一个异步请求回来进行数据缓存,剩下组件直接读取缓存来获取配置数据。

我想了一下,使用axios的拦截器把请求拦截下来处理,但是如何让剩下的组件进行等待呢?或者有什么其他思路?

共有3个答案

范飞翰
2023-12-14

直接使用 @tanstack/react-query

华子航
2023-12-14

正好昨天处理了一个类似的问题,按理说这种公共组件最好别有请求,但团队里其他人已经这么写了,而且代码已经测试过了,所以不好大改。
我这边是用一个单例去保存每次请求的结果,最后一段代码里的1000代表缓存的超时时间为1000ms(1s),如果在1s内一个请求再次发起,如果这个请求和上次请求的参数一致,就使用上次的缓存,当然如果上次请求还在pending,也不会重新发起,会一并等上次的结果。具体超时时间设多少看接口的特性,数据不会频繁变的话,设十几二十秒也可以。
最后用这个hook返回的apiCall去替换之前的请求方法就行。

import { useCallback, useState } from "react";import { isEqual } from "lodash";interface ResponseInfo {  params: unknown[];  lastRequestTime: number;  getData: () => Promise<unknown>;}type PromiseValue<T> = T extends Promise<infer U> ? U : T;// eslint-disable-next-line @typescript-eslint/no-explicit-anytype CommonFunc = (...p: any[]) => any;type ResponseData<T> = {  data: T;  isSuccess: boolean;  isError: boolean;};type ResponseValue<F extends CommonFunc> = {  apiCall: F;  data: ResponseData<PromiseValue<ReturnType<F>>>;  loading: boolean;};const responseWeakMap = new WeakMap<CommonFunc, ResponseInfo>();const genUseSingletonApi =  <T extends CommonFunc>(apiCall: T) =>  (instance: CommonFunc, expiration: number) =>  () => {    type APIReturnData = PromiseValue<ReturnType<typeof apiCall>>;    const [data, setData] = useState<APIReturnData>();    const [loading, setLoading] = useState<boolean>();    const apiCallFunc = useCallback(      async (...params: Parameters<T>) => {        setLoading(true);        const endCallback = (res: APIReturnData) => {          setLoading(false);          setData(res);        };        const requestInfo = responseWeakMap.get(instance);        if (requestInfo) {          const { getData: getResponseInfo, params: oldParams, lastRequestTime } = requestInfo;          const hasResponse =            isEqual(oldParams, params) && +new Date() - lastRequestTime <= expiration;          if (hasResponse) {            const res = await getResponseInfo();            endCallback(res as APIReturnData);            return res;          }        }        let resolve: (value: APIReturnData) => void = () => {};        const promise: Promise<APIReturnData> = new Promise(resolveCb => {          resolve = resolveCb;        });        responseWeakMap.set(instance, {          getData: () => promise,          params,          lastRequestTime: +new Date(),        });        const result = await apiCall(...params);        resolve(result);        endCallback(result);        return result;      },      [],    );    return {      apiCall: apiCallFunc,      data,      loading,    };  };const someAPISingletonInstance = genUseSingletonApi(fetchDataFunc);export const useAccountingList = someAPISingletonInstance(  someAPISingletonInstance,  1000,);
茹正祥
2023-12-14

这个问题可以通过使用React的状态钩子(useState)和副作用钩子(useEffect)来解决。

首先,我们需要在组件A中创建一个状态来存储配置数据。然后,我们使用useEffect钩子来处理异步请求。当组件挂载时,我们发送异步请求并更新状态。当组件卸载时,我们清除所有的定时器或订阅。

下面是一个简单的例子:

import React, { useState, useEffect } from 'react';import axios from 'axios';function ComponentA() {  const [configData, setConfigData] = useState(null);  useEffect(() => {    const fetchData = async () => {      try {        const response = await axios.get('your-api-url');        setConfigData(response.data);      } catch (error) {        console.error(error);      }    };    fetchData();  }, []); // 注意,这里依赖项数组为空,这意味着这个effect只在组件挂载和卸载时运行。  // 在这里,你可以根据需要返回一个loading状态或者一个错误消息,直到数据被成功获取。  if (!configData) {    return <div>Loading...</div>;  }  return <div>{configData}</div>;}

在这个例子中,每次组件A挂载时,都会发送一个异步请求来获取配置数据。然后,这个数据会被存储在状态中,所以其他组件可以访问它。当组件A卸载时,所有的异步请求都会被清除。这样,如果其他组件也使用了相同的配置数据,它们可以直接从状态中读取数据,而不需要再次发送请求。

此外,你也可以使用更复杂的逻辑来处理多个异步请求,例如使用Promise.all来等待所有的请求都完成。但是,这需要更复杂的代码,而且可能会导致其他组件在数据还未完全加载时就被渲染出来。因此,这个简单的例子应该足以满足你的需求。

 类似资料:
  • 问题内容: 我有一个场景,我将必须对服务器进行六个http调用才能获取六个不同项目的数据。这些服务器调用不能合并,并且它们就是那样。例如:如果您需要GOOGLE的报价信息,则向服务器发送请求,以请求google的报价信息。接下来,如果您需要Yahoo,则可以发起另一个http调用,依此类推。 情况如下: 现在,我的最终用户想要比较6家不同的公司。 正如我提到的那样,我不可避免地要使用6个异步任务进

  • (要求Workerman版本>=3.3.6) 安装: composer require react/dns 示例: <?php require_once __DIR__ . '/vendor/autoload.php'; use WorkermanWorker; $worker = new Worker('text://0.0.0.0:6161'); $worker->onWorkerStart

  • (要求Workerman版本>=3.3.6) 注意: 此组件是第三方组件,可能会有潜在的bug,建议使用WorkermanMySQL组件。 安装: composer require react/mysql 示例: <?php require_once __DIR__ . '/vendor/autoload.php'; use WorkermanWorker; $worker = new Worke

  • 组件 package.json index.d.ts 使用 目前在使用的时候报错 如何在 index.d.ts 文件中正确声明这个组件

  • 我对Angular很陌生,很难掌握如何处理异步请求。 我有3个组件:父组件-AppComponent子组件-LoginComponent、NavbarComponent、仪表板组件、MainComponent、SidebarComponent 和一个AuthService 在日志组件上按“Login”按钮时,我需要将布尔值“true”传递给所有组件。在按下导航栏组件上的“注销”按钮时,我需要将布尔

  • 我用React构建了3个组件。他们是: 包装器 列表 列表项 如何管理单击的复选框的状态。我想Wrapper知道哪些复选框被选中。