首页 > 解决方案 > 带参数的 useApi 钩子

问题描述

我正在尝试使用带有多个参数的 useApi 钩子的第一个答案中描述的钩子 useAPI 但我有一个主要问题。在我的组件中,我在 url 本身中呈现 useAPI,而我的参数可能还没有值,这会导致错误。这些值来自不同的 API 调用。如何仅在定义参数时才使用参数渲染我的 useAPI 钩子?

我的代码如下所示:

const Availability = () => {
     [account, setAccount] = useState(0);
     const savedApiData = useAPI({
         endpoint:'/programs/${state.account.id}/', // The account obj comes from a different useAPI in this component
         requestType: 'POST',
         body: {
            siteIds: !state.siteId ? [] : [state.siteId] 
         }
     }); 
}

在第一次渲染时,API url 将显示“无法读取未定义的属性“id””的错误。

标签: reactjsapireact-hooks

解决方案


这真的很简单,在第四行中,您正在访问 的id属性state.account,但account这里是未定义的(可能是因为它不存在)。为了解决这个问题,你可以在state.account未定义时使用一个虚拟 id(但你肯定会从服务器得到一个 404,所以你必须处理它),或者根本不使用useApi。钩子真的很难修补,有时一个小的未处理的钩子用例可能会使它完全无用。

另一个想法可能是允许endpoint钩子配置参数成为一个函数(仅在请求时调用),并向该对象添加另一个布尔参数以控制是否应该完成请求。

然后,如果state.account是未定义的,则没有请求完成,该endpoint函数永远不会执行并且没有错误发生,当state.account有一个值时,钩子可以重新尝试启动请求,调用该endpoint函数,这次你没有错误。

示例(未测试):

const useApi = ({endpoint, requestType, body, doRequest = true}) => {
    const [data, setData] = useState({ fetchedData: [], isError: false, isFetchingData: false });
    useEffect(() => {
        if (doRequest) requestApi();
    }, [endpoint, doRequest]); // Retry request when doRequest's value changes
    const requestApi = async () => {
        // invoke endpoint if it is a function
        let endpointUrl = typeof endpoint === 'function' ? endpoint() : endpoint;
        let response = {};
        try {
            setData({ ...data, isFetchingData: true });
            console.log(endpointUrl);
            switch (requestType) {
                case 'GET':
                    return (response = await axios.get(endpointUrl));
                case 'POST':
                    return (response = await axios.post(endpointUrl, body));
                case 'DELETE':
                    return (response = await axios.delete(endpointUrl));
                case 'UPDATE':
                    return (response = await axios.put(endpointUrl, body));
                case 'PATCH':
                    return (response = await axios.patch(endpointUrl, body));
                default:
                    return (response = await axios.get(endpoint));
            }
        } catch (e) {
            console.error(e);
            setData({ ...data, isError: true });
        } finally {
            if (response.data) {
                setData({ ...data, isFetchingData: false, fetchedData: response.data.mainData });

            }
        }
    };
    return data;
};

用法:

const Availability = () => {
     [account, setAccount] = useState(0);
     const savedApiData = useAPI({
         endpoint: () => '/programs/${state.account.id}/', // Replace string literal with a factory function
         requestType: 'POST',
         body: {
            siteIds: !state.siteId ? [] : [state.siteId] 
         },
         doRequest: !!state.account, // Only request if account exists
     }); 
}

推荐阅读