#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. спасибо, добавление этого в массив зависимостей исправило это