【问题标题】:useApi hook with multiple parameters带有多个参数的 useApi 钩子
【发布时间】:2019-10-24 10:22:27
【问题描述】:

我有一个 useApi 自定义钩子,它接受一个带有多个参数的端点(url)。 当其中一个参数更改时,将呈现图形。 问题是当一个参数发生变化时,另一个参数也会发生变化,并且图形会被渲染两次。我该如何解决? 谢谢

  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;
};

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    有几个地方可以重构:

    首先,您可以通过将useEffect 中的data 依赖项转换为以下内容来摆脱它:

    setData(currentData => {
      return { ...currentData, isFetchingData: true }
    })
    

    其次,最重要的是,您应该将 requestApi 函数移动到 useEffect 内部,或者使用 useCallback 函数将其包装起来。

    最后,如果有多个渲染然后另一个渲染是完全可以的。因为您依赖于 useEffect 中的所有参数。

    您可以做的一件事是利用returning a function in useEffect在卸载期间取消 axios 请求

    所以这是你的代码的最终版本:

    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
    }
    

    我没有测试代码。但它应该工作。请试着告诉我发生了什么。

    【讨论】:

      猜你喜欢
      • 2020-03-19
      • 2020-01-12
      • 2019-04-14
      • 1970-01-01
      • 2017-08-04
      • 1970-01-01
      • 2020-07-31
      • 2019-07-05
      • 1970-01-01
      相关资源
      最近更新 更多