【问题标题】:How do I fix "useEffect has a missing dependency" in custom hook如何在自定义挂钩中修复“useEffect 缺少依赖项”
【发布时间】:2020-02-13 06:11:43
【问题描述】:

我正在使用自定义挂钩从 API 中获取一些数据,以便在一组 React 函数组件中使用。然而,esLint 抛出了一个可爱的警告:

React Hook useEffect 缺少一个依赖项:'fetchFromAPI'。任何一个 包含它或删除依赖数组。

我不认为这是一个依赖项,因为它在 useFetch() 内部。我需要这样做,因为我正在使用await。我究竟做错了什么?关闭这条线路的警告可以吗?还是我应该使用更规范的语法?

function useFetch (url) {
  const [data, setData] = useState(null);

  async function fetchFromAPI() {
    const json = await( await fetch(url) ).json();
    setData(json);
  }

  useEffect(() => {fetchFromAPI()},[url]);

  return data;
};

export {
  useFetch
};

【问题讨论】:

    标签: reactjs eslint react-hooks use-effect


    【解决方案1】:

    在您的自定义效果之外声明它,传递url 作为参数,returnjson 设置在useEffect

    async function fetchFromAPI(url) {
        const json = await( await fetch(url) ).json();
        return json
    }
    
    function useFetch (url) {
      const [data, setData] = useState(null);
    
      useEffect(() => {
          setData(fetchFromAPI(url))
      },[url]);
    
      return data;
    };
    

    或者直接在useEffect里面

    function useFetch (url) {
      const [data, setData] = useState(null);
    
      useEffect(() => {
          async function fetchFromAPI() {
             const json = await( await fetch(url) ).json();
             return json
          }
          setData(fetchFromAPI())
      },[url]);
    
      return data;
    };
    

    【讨论】:

    • 他们可能必须将 setData 添加到依赖项数组中以消除警告 [url, setData]
    • 没有。 setDatauseState 的 setter,不需要作为依赖项传递
    • linter 是否足够聪明,可以理解 setData 不应该被视为依赖项?在任何情况下,都可以通过使用注释 // eslint-disable-line react-hooks/exhaustive-deps 来消除此错误
    • 是的。 data 会抛出警告,但 setData 不会。禁用 eslint 几乎总是一个坏主意。更新程序版本也不会引发警告setData(oldData => ({...oldData, newProp: 'foo'}))
    • 问题是代码运行后两个版本的代码都会导致"TypeError: undefined is not a function (near '...data.map...')"。我怀疑这取决于setData(fetchFromAPI()) 调用,而不是在@Bhojendra 提供的异步函数中执行setData(json)。对不起:-(
    【解决方案2】:

    我建议你在 useEffect 内部定义异步函数:

    function useFetch (url) {
      const [data, setData] = useState(null);
      useEffect(() => {
        async function fetchFromAPI() {
          const json = await( await fetch(url) ).json();
          setData(json);
        }
        fetchFromAPI()
      },[url]);
    
      return data;
    };
    

    您可以查看doc faqs 中的有效示例,它在 useEffect 本身内部使用异步函数:

    function ProductPage({ productId }) {
      const [product, setProduct] = useState(null);
    
      useEffect(() => {
        // By moving this function inside the effect, 
        // we can clearly see the values it uses.
        async function fetchProduct() {
          const response = await fetch('http://myapi/product' + productId);
          const json = await response.json();
          setProduct(json);
        }
    
        fetchProduct();
      }, [productId]); // ✅ Valid because our effect only uses productId
      // ...
    }
    

    【讨论】:

      【解决方案3】:

      只需将你的函数移动到 useEffect 中,一切都会好起来的:

      import { useState, useEffect } from "react";
      
      function useFetch(url) {
        const [data, setData] = useState(null);
      
        useEffect(() => {
          async function fetchFromAPI() {
            const json = await (await fetch(url)).json();
            setData(json);
          }
          fetchFromAPI();
        }, [url]);
      
        return data;
      }
      
      export { useFetch };
      
      

      https://codesandbox.io/s/clever-cdn-8g0me

      【讨论】:

        【解决方案4】:
        async function fetchFromAPI(url) {
          return ( await fetch(url) ).json();
        }
        
        function useFetch (url) {
          const [data, setData] = useState(null);
        
          useEffect(() => {
            fetchFromAPI(url).then(setData);
          }, [url, setData, fetchFromAPI]);
        
          return data;
        };
        
        export {
          useFetch
        };
        
        1. 你可以稍作改动,然后提取fetchFromAPI,因为不是每次useFetch调用都创建,对单一职责也有好处。
        2. 如果您非常了解此代码,当然您可以关闭当前行的 linting,也可以添加其余的 setDatafetchFromAPI 参数。并且完全按照这个顺序。因为在重新渲染参数比较从第一个参数到最后一个参数时,最好将更改最多的参数放在第一位,因为每次更改下一个参数时都不检查未更改的参数,所以如果第一次更改,useEffect 不要需要检查其他并提前调用传递的函数

        【讨论】:

          猜你喜欢
          • 2020-09-03
          • 2020-07-12
          • 1970-01-01
          • 2021-05-14
          • 2020-03-24
          • 2020-12-13
          • 2020-05-27
          • 1970-01-01
          相关资源
          最近更新 更多