我正在尝试使用第一个答案中描述的钩子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"。
这真的很简单,在第四行中,您正在访问state.account
的id
属性,但此处account
未定义(可能是因为它不存在(。为了解决这个问题,你可以在未定义state.account
时使用虚拟 id(但你肯定会得到来自服务器的 404,所以你必须处理它(,或者根本不使用useApi
。钩子真的很难修补,有时钩子的一个小的未处理用例可能会使它完全无用。
另一个想法可能是允许endpoint
hook config 参数是一个函数(仅在请求时调用(,并向该对象添加另一个布尔参数以控制是否应该完成请求。
然后,如果未定义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
});
}