React 自定义钩子导致无限循环
React custom hook causes infinite loops
知道为什么这个带有 SWR 的自定义钩子会导致无限循环吗?
export const useOrganization = () => {
const [data, setData] = useState<OrganizationModel | undefined>();
const { organizationId } = useParams();
const { data: dataSWR } = useSWRImmutable<
AxiosResponse<Omit<OrganizationModel, 'id'>>
>(`organizations/${organizationId}`, api);
useEffect(() => {
if (dataSWR?.data && organizationId) {
setData({ id: organizationId, ...dataSWR.data });
console.log({ id: organizationId, ...dataSWR.data });
}
});
return data;
};
我需要从 API 获取数据并从 URL 参数添加缺少的 ID。如果我使用 setData(dataSWR.data),一切都很好。使用 setData({...dataSWR.data}) -> loop.
时会出现问题
需要根据场景使用useEffect
。当 dataSWR
使用新数据再次更改 useEffect
调用时。
您可以在 useEffect
挂钩中添加 dataSWR
作为依赖参数。
useEffect(() => { do something... }, [dataSWR])
示例:
export const useOrganization = () => {
const [data, setData] = useState<OrganizationModel | undefined>();
const { organizationId } = useParams();
const { data: dataSWR } = useSWRImmutable<AxiosResponse<Omit<OrganizationModel, 'id'>>>(`organizations/${organizationId}`, API);
useEffect(() => {
if (dataSWR?.data && organizationId) {
setData({ id: organizationId, ...dataSWR.data });
console.log({ id: organizationId, ...dataSWR.data });
};
},[dataSWR]);
return data;
};
钩子的用法:
const data = useOrganization()
useEffect
的依赖参数是 useEffect(callback, dependencies)
让我们探讨副作用和运行:
未提供:副作用在每次渲染后运行。
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// Runs after EVERY rendering
});
}
一个空数组[]:副作用在初始渲染后运行一次。
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// Runs ONCE after initial rendering
}, []);
}
有道具或状态值[prop1, prop2, ..., state1, state2]
:副作用仅在任何依赖值发生变化时运行。
import { useEffect, useState } from 'react';
function MyComponent({ prop }) {
const [state, setState] = useState('');
useEffect(() => {
// Runs ONCE after initial rendering
// and after every rendering ONLY IF `prop` or `state` changes
}, [prop, state]);
}
我找到了解决方案 - useMemo hook:
export const useOrganization = () => {
const { organizationId } = useParams();
const { data } = useSWRImmutable<
AxiosResponse<Omit<OrganizationModel, 'id'>>
>(`organizations/${organizationId}`, api);
const result = useMemo(() => {
if (data && organizationId) {
return { id: organizationId, ...data.data };
}
}, [data, organizationId]);
console.log('useOrganization');
return result;
};
知道为什么这个带有 SWR 的自定义钩子会导致无限循环吗?
export const useOrganization = () => {
const [data, setData] = useState<OrganizationModel | undefined>();
const { organizationId } = useParams();
const { data: dataSWR } = useSWRImmutable<
AxiosResponse<Omit<OrganizationModel, 'id'>>
>(`organizations/${organizationId}`, api);
useEffect(() => {
if (dataSWR?.data && organizationId) {
setData({ id: organizationId, ...dataSWR.data });
console.log({ id: organizationId, ...dataSWR.data });
}
});
return data;
};
我需要从 API 获取数据并从 URL 参数添加缺少的 ID。如果我使用 setData(dataSWR.data),一切都很好。使用 setData({...dataSWR.data}) -> loop.
时会出现问题需要根据场景使用useEffect
。当 dataSWR
使用新数据再次更改 useEffect
调用时。
您可以在 useEffect
挂钩中添加 dataSWR
作为依赖参数。
useEffect(() => { do something... }, [dataSWR])
示例:
export const useOrganization = () => {
const [data, setData] = useState<OrganizationModel | undefined>();
const { organizationId } = useParams();
const { data: dataSWR } = useSWRImmutable<AxiosResponse<Omit<OrganizationModel, 'id'>>>(`organizations/${organizationId}`, API);
useEffect(() => {
if (dataSWR?.data && organizationId) {
setData({ id: organizationId, ...dataSWR.data });
console.log({ id: organizationId, ...dataSWR.data });
};
},[dataSWR]);
return data;
};
钩子的用法:
const data = useOrganization()
useEffect
的依赖参数是 useEffect(callback, dependencies)
让我们探讨副作用和运行:
未提供:副作用在每次渲染后运行。
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// Runs after EVERY rendering
});
}
一个空数组[]:副作用在初始渲染后运行一次。
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// Runs ONCE after initial rendering
}, []);
}
有道具或状态值[prop1, prop2, ..., state1, state2]
:副作用仅在任何依赖值发生变化时运行。
import { useEffect, useState } from 'react';
function MyComponent({ prop }) {
const [state, setState] = useState('');
useEffect(() => {
// Runs ONCE after initial rendering
// and after every rendering ONLY IF `prop` or `state` changes
}, [prop, state]);
}
我找到了解决方案 - useMemo hook:
export const useOrganization = () => {
const { organizationId } = useParams();
const { data } = useSWRImmutable<
AxiosResponse<Omit<OrganizationModel, 'id'>>
>(`organizations/${organizationId}`, api);
const result = useMemo(() => {
if (data && organizationId) {
return { id: organizationId, ...data.data };
}
}, [data, organizationId]);
console.log('useOrganization');
return result;
};