问题描述
我们在此fairly decent tutorial的最底部编写了一个自定义数据获取挂钩useInternalApi
,类似于使用反应挂钩进行数据获取的JSFiddle底部的useDataApi
挂钩。我们的应用程序获取了大量体育数据,特别是,我们正在尝试为我们的用例找出正确的数据获取模式,这很简单:
为此,我们的代码将如下所示:
import `useInternalApi` from '../path-to-hooks/useInternalApi';
// import React... and other stuff
function ComponentThatWantsTeamInfo({ conferenceId }) {
// use data fetching hook
const [conferenceInfo,isLoading1,isError1] = useInternalApi('conferenceInfo',{ conferenceId: conferenceId })
// once conferenceInfo loads,then load info from all teams in the conference
if (conferenceInfo && conferenceInfo.teamsArray) {
const [teamInfos,isLoading2,isError2] = useInternalApi('teamInfo',{ teamIds: conferenceInfo.teamIds })
}
}
在上面的示例中,conferenceId
是整数,teamIds
是整数数组,并且useInternalApi
函数的两个参数的组合创建了一个唯一的端点url以进行提取数据来自。当前与此有关的两个主要问题是:
什么是正确的数据获取模式?理想情况下,teamInfos
将是一个对象,其中每个密钥是会议中一个团队的teamId
。特别是:
- 创建一个新的内部钩子,该钩子可以处理teamId的数组,将进行10-20次提取(或根据
teamsArray
的长度进行所需的提取),并使用Promise.all()一起返回结果。 - 按原样保留
useInternalApi
钩子,并简单地将其称为10-20次,每个团队一次。
编辑
我不确定是否需要useInternalApi
的基础代码来回答这个问题。我尽量避免创建很长的帖子,但是在这种情况下,也许该代码很重要:
const useInternalApi = (endpoint,config) => {
// Set Data-Fetching State
const [data,setData] = useState(null);
const [isLoading,setIsLoading] = useState(true);
const [isError,setIsError] = useState(false);
// Use in lieu of useEffect
useDeepCompareEffect(() => {
// Token/Source should be created before "fetchData"
let source = axios.CancelToken.source();
let isMounted = true;
// Create Function that makes Axios requests
const fetchData = async () => {
// Set States + Try To Fetch
setIsError(false);
setIsLoading(true);
try {
const url = createUrl(endpoint,config);
const result = await axios.get(url,{ cancelToken: source.token });
if (isMounted) {
setData(result.data);
}
} catch (error) {
if (isMounted) {
setIsError(true);
}
} finally {
if (isMounted) {
setIsLoading(false);
}
}
};
// Call Function
fetchData();
// Cancel Request / Prevent State Updates (Memory Leaks) in cleanup function
return () => {
isMounted = false; // set to false to prevent state updates / memory leaks
source.cancel(); // and cancel the http request as well because why not
};
},[endpoint,config]);
// Return as length-3 array
return [data,isLoading,isError];
};
解决方法
我认为,如果需要有条件地使用挂钩,则应在单独的组件内部使用该挂钩,然后有条件地渲染该组件。
我的理解,如果我错了,请纠正我,是因为最初的API调用返回了一个ID数组,您需要基于该ID来获取每个团队的数据吗?
这就是我要做那种事情的方式。
import `useInternalApi` from '../path-to-hooks/useInternalApi';
// import React... and other stuff
function ComponentThatDisplaysASpecificTeam(props){
const teamId = props.teamId;
const [teamInfo] = useInternalApi('teamInfo',{ teamId });
if(! teamInfo){
return <p>Loading...</p>
}
return <p>do something with teamInfo...</p>
}
function ComponentThatWantsTeamInfo({ conferenceId }) {
// use data fetching hook
const [conferenceInfo,isLoading1,isError1] = useInternalApi('conferenceInfo',{ conferenceId: conferenceId })
if (! conferenceInfo || ! conferenceInfo.teamsArray) {
return <p>this is either a loading or an error,you probably know better than me.</p>
}
// Let the data for each team be handled by its own component. This also lets you not have to use Promise.all
return (
<div>
{conferenceInfo.teamIds.map(teamId => (
<ComponentThatDisplaysASpecificTeam teamId={teamId} />
))}
</div>
)
}