I'm using the swr package. I successfully fetch data using useSWR, but when I try to mutate the data - it does not work, and the cached state of swr does not change (as it should).
I created my custom hook:
import useSWR from 'swr';
import BackendService from '@/services/backend';
const useBackend = <D, E = unknown>(path: string | null) => {
const { data, error, isLoading, mutate } = useSWR<D, E>(path, BackendService.get);
return { data, error, isLoading, mutate };
};
export default useBackend;
And this is my BackendService:
import { preload } from 'swr';
import type { IHttpMethod } from '@/interfaces/http';
class BackendService {
private static routesWithRefreshToken: string[] = ['/user/auth'];
private static fetcher = async <R = unknown, D = unknown>(
path: string,
method: IHttpMethod,
data?: D,
) => {
const requestPath = import.meta.env.VITE_BACKEND_URL + path;
const withRefresh = this.routesWithRefreshToken.includes(path);
const token = withRefresh ? localStorage.getItem('token') : sessionStorage.getItem('token');
const res = await fetch(requestPath, {
method,
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: data ? JSON.stringify(data) : undefined,
});
if (!res.ok) {
throw new Error();
}
const resData = await res.json().catch(() => undefined);
return resData as R;
};
public static get = <R = unknown>(path: string) => {
return this.fetcher<R, null>(path, 'GET');
};
public static post = <R = unknown, D = unknown>(path: string, data?: D) => {
return this.fetcher<R, D>(path, 'POST', data);
};
public static patch = <R = unknown, D = unknown>(path: string, data?: D) => {
return this.fetcher<R, D>(path, 'PATCH', data);
};
public static delete = <R = unknown>(path: string) => {
return this.fetcher<R, null>(path, 'DELETE');
};
public static preload = (path: string) => {
return preload(path, this.get);
};
}
export default BackendService;
Now, I have the following code:
import React, { useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import type { IGetAllSecretsResponseData } from '@exlint.io/common';
import useBackend from '@/hooks/use-backend';
import BackendService from '@/services/backend';
import SecretManagementView from './SecretManagement.view';
interface IProps {}
const SecretManagement: React.FC<IProps> = () => {
const navigate = useNavigate();
const { data: getAllSecretsResponseData, mutate: getAllSecretsMutate } =
useBackend<IGetAllSecretsResponseData>('/user/secrets');
const hasSecrets = useMemo(() => {
if (!getAllSecretsResponseData) {
return false;
}
return getAllSecretsResponseData.secrets.length > 0;
}, [getAllSecretsResponseData]);
const onRevokeAllSecrets = async () => {
await getAllSecretsMutate(
async () => {
await BackendService.delete('/user/secrets');
return {
secrets: [],
};
},
{
optimisticData: { secrets: [] },
rollbackOnError: true,
},
);
navigate('', { replace: true });
};
return <SecretManagementView hasSecrets={hasSecrets} onRevokeAllSecrets={onRevokeAllSecrets} />;
};
SecretManagement.displayName = 'SecretManagement';
SecretManagement.defaultProps = {};
export default React.memo(SecretManagement);
So when the onRevokeAllSecrets is executed - the cached state does not change.
But if I use mutate of useSWRConfig it works:
import React, { useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import type { IGetAllSecretsResponseData } from '@exlint.io/common';
import { useSWRConfig } from 'swr';
import useBackend from '@/hooks/use-backend';
import BackendService from '@/services/backend';
import SecretManagementView from './SecretManagement.view';
interface IProps {}
const SecretManagement: React.FC<IProps> = () => {
const navigate = useNavigate();
const { mutate } = useSWRConfig();
const { data: getAllSecretsResponseData, mutate: getAllSecretsMutate } =
useBackend<IGetAllSecretsResponseData>('/user/secrets');
const hasSecrets = useMemo(() => {
if (!getAllSecretsResponseData) {
return false;
}
return getAllSecretsResponseData.secrets.length > 0;
}, [getAllSecretsResponseData]);
const onRevokeAllSecrets = async () => {
await getAllSecretsMutate(
async () => {
await BackendService.delete('/user/secrets');
return {
secrets: [],
};
},
{
optimisticData: { secrets: [] },
rollbackOnError: true,
},
);
mutate('/user/secrets', { secrets: [] });
navigate('', { replace: true });
};
return <SecretManagementView hasSecrets={hasSecrets} onRevokeAllSecrets={onRevokeAllSecrets} />;
};
SecretManagement.displayName = 'SecretManagement';
SecretManagement.defaultProps = {};
export default React.memo(SecretManagement);
Could anyone tell why? I checked and my BackendService.delete call completes successfully.
from SWR mutation does not update the cache using a static method of class as a fetcher
No comments:
Post a Comment