【问题标题】:useEffect infinitely loops when I include a dependency当我包含依赖项时,useEffect 无限循环
【发布时间】:2020-12-13 14:47:55
【问题描述】:

我正在尝试创建一个自定义 useFetch 钩子,它适用于除一个之外的每个组件。在这一个组件中,它无限循环(但没有那么多 React 停止它)。这是钩子:

import { useState, useEffect, SetStateAction, Dispatch } from 'react';
import axios, { AxiosResponse } from 'axios';

const useFetch = (
  method: 'POST' | 'GET',
  url: string,
  object?: any
): [
  AxiosResponse,
  'Loading' | 'Rendered' | 'Error',
  Dispatch<SetStateAction<'Loading' | 'Rendered' | 'Error'>>
] => {
  const [data, setData] = useState<AxiosResponse | null | void>(null);
  const [compState, setCompState] = useState<'Loading' | 'Rendered' | 'Error'>('Loading');

  useEffect(() => {
    let isMounted = true;
    setCompState('Loading');
    if (method === 'GET') {
      // ...
    } else if (
      method === 'POST' &&
      object !== null &&
      !Object.values(object).includes(null)
    ) {
      axios
        .post(url, object)
        .then(res => {
          if (isMounted) {
            console.log(res.data);
            setCompState('Rendered');
            setData(res);
          }
        })
        .catch(err => {
          if (isMounted) {
            console.log(err);
            setCompState('Error');
            setData(err);
          }
        });
    } else return;

    return () => {
      isMounted = false;
    };
  }, [url, object]); 

  return [data as AxiosResponse, compState];
};

export default useFetch;

这是我在组件中使用它的方式:

  const userId = localStorage.getItem('userId');
  const [orders, compState] = useFetch('POST', '/orders', { userId });

我知道导致循环的部分原因;这是因为我在依赖数组中有object,如果我从数组中删除它,它就会停止循环。问题是我需要数组中的object,因为在这种情况下,对象只是 userId,我希望在用户登录此页面时重新呈现组件。我认为有关 userId 常量的某些东西是导致此问题的原因。

在我提取自定义钩子之前,常量在 useEffect 中,这不是问题,但我想知道他们的解决方法是否不会影响钩子的可重用性。

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    如果您想对该对象进行深入的属性比较,则不应将objects 作为第二个useEffect 参数的数组项传递,因此如果您需要对objects 属性进行深入比较,最好的方法是使用use-deep-compare-effect 如下:

    import useDeepCompareEffect from 'use-deep-compare-effect';
    
    // Later in our components
    useDeepCompareEffect(() => {
        let isMounted = true;
        setCompState('Loading');
        if (method === 'GET') {
          // ...
        } else if (
          method === 'POST' &&
          object !== null &&
          !Object.values(object).includes(null)
        ) {
          axios
            .post(url, object)
            .then(res => {
              if (isMounted) {
                console.log(res.data);
                setCompState('Rendered');
                setData(res);
              }
            })
            .catch(err => {
              if (isMounted) {
                console.log(err);
                setCompState('Error');
                setData(err);
              }
            });
        } else return;
    
        return () => {
          isMounted = false;
        };
      }, [url, object]); 
    

    【讨论】:

      【解决方案2】:

      我认为您可以尝试如下,因为 useEffect 使用 浅比较,所以 2 个对象 {} 和 {} 不一样,然后会导致无限渲染.

      JSON.stringify(object)
      

      【讨论】:

      • 谢谢,将这个添加到依赖数组修复它
      猜你喜欢
      • 2021-09-27
      • 2021-07-25
      • 2020-11-10
      • 2020-11-02
      • 2021-01-08
      • 2020-01-11
      • 2019-10-25
      • 1970-01-01
      相关资源
      最近更新 更多