使用React 16.8.6(在之前的版本16.8.3上很好),当我试图阻止fetch请求上的无限循环时,我得到了这个错误:

./src/components/BusinessesList.js
Line 51:  React Hook useEffect has a missing dependency: 'fetchBusinesses'.
Either include it or remove the dependency array  react-hooks/exhaustive-deps

我一直无法找到一个解决办法来停止这个无限循环。我想远离使用useReducer()。我确实找到了关于'筋疲力尽-deps' lint规则#14920的讨论[ESLint]反馈,其中一个可能的解决方案是,如果你认为你知道你在做什么,你可以总是// ESLint - disabled -next-line react-hooks/详尽-deps。我对我正在做的事情没有信心,所以我还没有尝试实现它。

我有这个当前的设置,React钩子useEffect连续运行永远/无限循环,唯一的评论是关于useCallback(),我不熟悉。

我目前如何使用useEffect()(我只想在开始时运行一次,类似componentDidMount()):

useEffect(() => {
    fetchBusinesses();
  }, []);
const fetchBusinesses = () => {
    return fetch("theURL", {method: "GET"}
    )
      .then(res => normalizeResponseErrors(res))
      .then(res => {
        return res.json();
      })
      .then(rcvdBusinesses => {
        // some stuff
      })
      .catch(err => {
        // some error handling
      });
  };

当前回答

使用UseEffect fetchBusinesses调用UseEffect()中的function declare,在调用函数名后声明一个const变量,

useEffect(()=>{
const fetchBusinesses=()=>{
   console.log(useeffect fetchbussinesses functions)
}
 fetchBusinesses();
},[declare the variable used in useeffect hooks ])

其他回答

好吧,如果你想从不同的角度来看这个问题,你只需要知道React有哪些非耗尽的选项。你不应该在效果中使用闭包函数的原因之一是在每次渲染时,它都会被重新创建/销毁。

因此,钩子中有多个React方法被认为是稳定的和非耗尽的,在这些方法中,您不必应用到useEffect依赖项,并且反过来也不会破坏React -hooks/竭-deps的约定规则。例如,useReducer或useState的第二个返回变量是一个函数。

const [,dispatch] = useReducer(reducer, {});

useEffect(() => {
    dispatch(); // Non-exhausted - ESLint won't nag about this
}, []);

所以反过来,你可以让所有的外部依赖关系与你在reducer函数中的当前依赖关系共存。

const [,dispatch] = useReducer((current, update) => {
    const { foobar } = update;
    // Logic

    return { ...current, ...update };
}), {});

const [foobar, setFoobar] = useState(false);

useEffect(() => {
    dispatch({ foobar }); // non-exhausted `dispatch` function
}, [foobar]);

如果在useEffect中使用的变量是在组件内部定义的,或者是作为道具传递给组件的,则会发生此警告。因为你在同一个组件中定义了fetchBusinesses(),而eslint遵循这一规则,你必须将它传递给依赖数组。但在您的情况下,只传递[]也可以

在这种情况下,它将工作,但如果fetchBusinesses在函数中使用setState,并且调用它将重新呈现组件,因此您的fetchBusinesses将改变,因此useEffect将运行,这将创建一个无限循环。因此,仅仅盲目地遵循eslint可能会导致额外的错误。

用例解决方案让eslint满意,使用useCallback和[]。

const memoizedFetchBusinesses=useCallback(
        fetchBusinesses,
        [] // unlike useEffect you always have to pass a dependency array
       )

当组件第一次呈现时,在内存中创建一个名为fetchBusinessess的函数,并创建memoizedFetchBusinesses变量,该变量也在内存中引用相同的函数。

在第一次渲染之后,一个被称为fetchbusiness的函数将再次被创建,但这一次在不同的内存位置,因为我们在useCallback中有[],memoizedFetchBusinesses将在相同的内存中给你原始的fetchBusinesses函数。这里的useCallback将为您提供在组件的第一次呈现中创建的相同的函数引用。

useEffect(()=>{
    memoizedFetchBusinesses();
},[memoizedFetchBusinesses]) 

相反,你可以这样定义函数

const fetchBusinesses = useCallback(() => {
    return fetch("theURL", {method: "GET"}
    )
      .then(res => normalizeResponseErrors(res))
      .then(res => {
        return res.json();
      })
      .then(rcvdBusinesses => {
        // some stuff
      })
      .catch(err => {
        // some error handling
      });
  },[]);

然后在useEffect中

useEffect(() => {
    fetchBusinesses();
  }, [fetchBusinesses]);

React也给出了解决方案。他们建议你使用useCallback,它会返回你函数的一个内存版本:

'fetchBusinesses'函数使useEffect钩子(在NN行)的依赖关系在每次渲染时发生变化。为了解决这个问题,将'fetchBusinesses'定义包装到它自己的useCallback() Hook react-hooks/竭-deps中

useCallback使用起来很简单,因为它与useEffect具有相同的签名。区别在于useCallback返回一个函数。 它看起来是这样的:

 const fetchBusinesses = useCallback( () => {
        return fetch("theURL", {method: "GET"}
    )
    .then(() => { /* Some stuff */ })
    .catch(() => { /* Some error handling */ })
  }, [/* deps */])
  // We have a first effect that uses fetchBusinesses
  useEffect(() => {
    // Do things and then fetchBusinesses
    fetchBusinesses();
  }, [fetchBusinesses]);
   // We can have many effects that use fetchBusinesses
  useEffect(() => {
    // Do other things and then fetchBusinesses
    fetchBusinesses();
  }, [fetchBusinesses]);

你可以这样尝试:

const fetchBusinesses = () => {
    return fetch("theURL", {method: "GET"})
        .then(res => normalizeResponseErrors(res))
        .then(res => {
            return res.json();
        })
        .then(rcvdBusinesses => {
            // Some stuff
        })
        .catch(err => {
            // Some error handling
        });
  };

and

useEffect(() => {
    fetchBusinesses();
});

这对你有用。

但我的建议是试试这种方法,它也适用于你。 这比以前的方法好。我是这样用的:

useEffect(() => {
    const fetchBusinesses = () => {
        return fetch("theURL", {method: "GET"})
            .then(res => normalizeResponseErrors(res))
            .then(res => {
                return res.json();
            })
            .then(rcvdBusinesses => {
                // Some stuff
            })
            .catch(err => {
                // Some error handling
            });
    };

    fetchBusinesses();
}, []);

如果您根据特定的id获取数据,则在回调中添加useEffect [id]。然后它就不能显示警告 React钩子useEffect有一个缺失的依赖:'any thing'。要么包含它,要么删除依赖数组

你正在使用useEffect,当你这样做的时候,你经常会想要使用一些变量作为你的组件中的道具或状态。

eslint中有一个规则,它希望你引用useEffect依赖数组中任何不同的道具或状态块。这是控制何时执行useEffect的数组。该规则希望看到它列在数组中,数组决定何时重新运行useEffect函数。

因此,您需要添加[fetchBusinesses],这样警告就会消失。

为什么这个规则要我们把它写在这里?

在某些情况下,使用useEffect而没有正确列出数组内的所有状态和道具,可能会导致奇怪且难以调试的问题。

因此,这条规则有助于避免使用useEffect可能出现的那些难以理解的问题。

现在,任意添加到该数组也会导致错误。所以无论哪种方式,你都遇到了必须解决的bug。根据你的评论,似乎为你解决了这个问题,但我想进一步调查,看看你是否有机会在你的网络选项卡在Chrome中添加fetchBusinesses函数到你的useEffect数组后得到第二个GET请求。