带有多个参数的 useApi 钩子 [英] useApi hook with multiple parameters

查看:49
本文介绍了带有多个参数的 useApi 钩子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆