首页 > 解决方案 > 当我包含依赖项时,useEffect 无限循环

问题描述

我正在尝试创建一个自定义 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 中,这不是问题,但我想知道他们是否有一种解决此问题的方法,不会影响钩子的可重用性。

标签: javascriptreactjsreact-hooks

解决方案


如果您想要对该对象进行深度属性比较,则不应将objects其作为第二个参数的数组项传递,因此如果您需要对s 属性进行深度比较,最好的方法是使用如下:useEffectobjectuse-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]); 

推荐阅读