带有多个参数的 useApi 钩子 [英] useApi hook with multiple parameters
问题描述
我有一个 useApi 自定义钩子,它接受一个带有多个参数的端点 (url).当其中一个参数发生变化时,就会呈现一个图形.问题在于,当一个参数发生变化时,另一个参数也会发生变化,并且图形会呈现两次.我该如何解决?谢谢
I have a useApi custom hook, that takes an endpoint (url) with multiple parameters. When one of the parameters changes a graph is rendered. The problem is that when one parameter changes, another parameter is changing as well and the graph is rendered twice. How can I solve it? Thanks
const useApi = (endpoint, requestType, body) => {
const [data, setData] = useState({ fetchedData: [], isError: false, isFetchingData: false });
useEffect(() => {
requestApi();
}, [endpoint]);
const requestApi = async () => {
let response = {};
try {
setData({ ...data, isFetchingData: true });
console.log(endpoint);
switch (requestType) {
case 'GET':
return (response = await axios.get(endpoint));
case 'POST':
return (response = await axios.post(endpoint, body));
case 'DELETE':
return (response = await axios.delete(endpoint));
case 'UPDATE':
return (response = await axios.put(endpoint, body));
case 'PATCH':
return (response = await axios.patch(endpoint, 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;
};
推荐答案
有几个地方可以重构:
首先,您可以通过将useEffect
中的data
依赖转换为这样的内容来摆脱它:
First, you can get rid of data
dependency in your useEffect
by converting it to something like this:
setData(currentData => {
return { ...currentData, isFetchingData: true }
})
第二,也是最重要的一点,您应该将 requestApi
函数移到 useEffect
内部,或者用 useCallback
函数将其包装起来.
As second and most importantly, you should either move your requestApi
function to inside of the useEffect
or wrap it with a useCallback
function.
最后,如果有多个渲染然后另一个渲染是完全可以的.因为您依赖于 useEffect
中的所有参数.
And finally, It is totally OK if there are multiple renders followed by another. Because you are depending on all params inside of your useEffect
.
您可以做的一件事是在卸载期间取消 axios 请求,利用 在 useEffect 中返回一个函数.
One thing that you can do is canceling the axios requests during the unmount by taking advantage of returning a function in useEffect.
这里是您的代码的最终版本:
So here is the final version of your code:
const useApi = (endpoint, requestType, body) => {
const [data, setData] = useState({
fetchedData: [],
isError: false,
isFetchingData: false
})
useEffect(() => {
let axiosSource = axios.CancelToken.source() // generate a source for axios
let didCancel = false // we can rely on this variable.
const requestApi = async () => {
let response = {}
try {
setData(data => {
return { ...data, isFetchingData: true }
})
console.log(endpoint)
const axiosOptions = { cancelToken: axiosSource.token }
switch (requestType) {
case 'GET':
return (response = await axios.get(endpoint, axiosOptions))
case 'POST':
return (response = await axios.post(endpoint, body, axiosOptions))
case 'DELETE':
return (response = await axios.delete(endpoint, axiosOptions))
case 'UPDATE':
return (response = await axios.put(endpoint, body, axiosOptions))
case 'PATCH':
return (response = await axios.patch(endpoint, body, axiosOptions))
default:
return (response = await axios.get(endpoint, axiosOptions))
}
} catch (e) {
console.error(e)
if (!didCancel) {
setData(data => {
return { ...data, isError: true }
})
}
} finally {
// do not update the data if the request is cancelled
if (response.data && !didCancel) {
setData(data => {
return {
...data,
isFetchingData: false,
fetchedData: response.data.mainData
}
})
}
}
}
requestApi()
// Here we are saying to axios cancel all current ongoing requests
// since this is the cleanup time.
return () => {
didCancel = true
axiosSource.cancel()
}
}, [body, endpoint, requestType])
return data
}
我没有测试代码.但它应该工作.请试着告诉我发生了什么.
I did not test the code. But it should be working. Please try and tell me what happened.
这篇关于带有多个参数的 useApi 钩子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!