React中组件A里有个获取配置数据的异步请求,列表中多个组件A就会触发多个相同的异步请求,期望是等到第一个异步请求回来进行数据缓存,剩下组件直接读取缓存来获取配置数据。
我想了一下,使用axios的拦截器把请求拦截下来处理,但是如何让剩下的组件进行等待呢?或者有什么其他思路?
直接使用 @tanstack/react-query
正好昨天处理了一个类似的问题,按理说这种公共组件最好别有请求,但团队里其他人已经这么写了,而且代码已经测试过了,所以不好大改。
我这边是用一个单例去保存每次请求的结果,最后一段代码里的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,);
这个问题可以通过使用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
我对Angular很陌生,很难掌握如何处理异步请求。 我有3个组件:父组件-AppComponent子组件-LoginComponent、NavbarComponent、仪表板组件、MainComponent、SidebarComponent 和一个AuthService 在日志组件上按“Login”按钮时,我需要将布尔值“true”传递给所有组件。在按下导航栏组件上的“注销”按钮时,我需要将布尔
我用React构建了3个组件。他们是: 包装器 列表 列表项 如何管理单击的复选框的状态。我想Wrapper知道哪些复选框被选中。
(要求Workerman版本>=3.3.6) 安装: composer require react/http-client 示例: <?php require_once __DIR__ . '/vendor/autoload.php'; use WorkermanWorker; $worker = new Worker('text://0.0.0.0:6161'); $worker->onWork