1

我们编写了一个自定义的数据获取钩子useInternalApi,它类似于这个相当不错的使用反应钩子获取数据的教程useDataApi底部的钩子。我们的应用程序获取大量体育数据,特别是,我们正在尝试为我们的用例找出正确的数据获取模式,这相当简单:

  • 获取特定实体的一般信息(例如 NCAA 会议)
  • 使用该实体返回的信息(特定会议中团队的团队 ID 数组),并获取数组中每个团队的信息。

为此,我们的代码将如下所示:

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函数的 2 个参数的组合创建了一个唯一的端点 url 来从中获取数据。目前这方面的两个主要问题是:

  1. 我们的useInternalApi钩子在一个语句中被调用if,这在 #1 的钩子规则中是不允许的。
  2. useInternalApi当前构建为仅对特定端点进行一次提取。目前,它不能像上面那样处理一组 teamId。

什么是正确的数据获取模式?理想情况下,teamInfos将是一个对象,其中每个键都是teamId会议中的一个团队的。特别是,是否更好:

  1. 创建一个新的内部钩子,它可以处理一个团队 ID 数组,将进行 10 到 20 次提取(或根据 的长度所需的次数teamsArray),并将使用 Promise.all() 一起返回结果。
  2. 保持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];
};
4

1 回答 1

1

在我看来,如果您需要有条件地使用钩子,您应该在单独的组件内使用该钩子,然后有条件地渲染该组件。

我的理解,如果我错了,请纠正我,是初始 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>
    )

}
于 2020-09-06T20:24:00.443 回答