如何修复自定义钩子中的“useEffect 缺少依赖项”

IT技术 reactjs eslint react-hooks use-effect
2021-05-10 22:16:38

我正在使用自定义钩子从 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
};
4个回答

我建议你在 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 本身内部使用 async 函数:

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
  // ...
}

在您的自定义效果之外声明它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;
};

只需将您的函数移动到 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

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参数。并且完全按照这个顺序。因为re-render params比较是从第一个param到最后一个,最好把变化最多的param放在第一位,因为每次下一个变化时不检查未变化的param,所以如果是第一次变化,useEffect不需要检查其他人并提前调用传递的函数