Files
twenty/packages/twenty-front/src/modules/client-config/hooks/useClientConfig.ts
Raphaël Bosi 2f89b36693 Fix ClientConfigProviderEffect infite loop (#12472)
Fixes an infinite loop introduced by #12371

An infinite loop was triggered when there was an error when fetching the
client config.
Cause of the bug: `isLoadedOnce` wasn't set to true when catching an
error in `useClientConfig`.

This effect then created an infinite loop inside
`ClientConfigProviderEffect` because `fetchClientConfig` updated
`clientConfigApiStatus.isLoading` but not `isLoadedOnce`.

```typescript
useEffect(() => {
    if (
      !clientConfigApiStatus.isLoadedOnce &&
      !clientConfigApiStatus.isLoading
    ) {
      fetchClientConfig();
    }
  }, [
    clientConfigApiStatus.isLoadedOnce,
    clientConfigApiStatus.isLoading,
    fetchClientConfig,
  ]);
```
2025-06-05 19:38:10 +02:00

58 lines
1.6 KiB
TypeScript

import { useCallback } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { ClientConfig } from '~/generated/graphql';
import { clientConfigApiStatusState } from '../states/clientConfigApiStatusState';
import { getClientConfig } from '../utils/getClientConfig';
type UseClientConfigResult = {
data: { clientConfig: ClientConfig } | undefined;
loading: boolean;
error: Error | undefined;
fetchClientConfig: () => Promise<void>;
refetch: () => Promise<void>;
};
export const useClientConfig = (): UseClientConfigResult => {
const clientConfigApiStatus = useRecoilValue(clientConfigApiStatusState);
const setClientConfigApiStatus = useSetRecoilState(
clientConfigApiStatusState,
);
const fetchClientConfig = useCallback(async () => {
setClientConfigApiStatus((prev) => ({
...prev,
isLoading: true,
}));
try {
const clientConfig = await getClientConfig();
setClientConfigApiStatus((prev) => ({
...prev,
isLoading: false,
isLoadedOnce: true,
isErrored: false,
error: undefined,
data: { clientConfig },
}));
} catch (err) {
const error =
err instanceof Error ? err : new Error('Failed to fetch client config');
setClientConfigApiStatus((prev) => ({
...prev,
isLoading: false,
isLoadedOnce: true,
isErrored: true,
error,
}));
}
}, [setClientConfigApiStatus]);
return {
data: clientConfigApiStatus.data,
loading: clientConfigApiStatus.isLoading || false,
error: clientConfigApiStatus.error,
fetchClientConfig,
refetch: fetchClientConfig,
};
};