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;
};