Использование эффекта бесконечных циклов при включении зависимости

#javascript #reactjs #react-hooks

#javascript #reactjs #реагирующие крючки

Вопрос:

Я пытаюсь создать пользовательский хук 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' amp;amp;
      object !== null amp;amp;
      !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.

До того, как я извлек пользовательский хук, константа была в useEffect, и это не было проблемой, но мне интересно, есть ли у них способ исправить это, который не влияет на возможность повторного использования хука.

Ответ №1:

Вы не должны передавать objects в качестве элемента массива второй useEffect параметр, если вам нужно глубокое сравнение свойств для этого объекта, поэтому лучший способ сделать это, если вам нужно глубокое сравнение object свойств s, — использовать 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' amp;amp;
      object !== null amp;amp;
      !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)
 

Комментарии:

1. спасибо, добавление этого в массив зависимостей исправило это