Tal*_*ofe 6 javascript typescript reactjs swr
我正在使用该swr包。我成功地使用 获取数据useSWR,但是当我尝试改变数据时 - 它不起作用,并且 的缓存状态swr不会改变(正如它应该的那样)。
我创建了自定义钩子:
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;
Run Code Online (Sandbox Code Playgroud)
这是我的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;
Run Code Online (Sandbox Code Playgroud)
现在,我有以下代码:
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);
Run Code Online (Sandbox Code Playgroud)
因此,当onRevokeAllSecrets执行时 - 缓存状态不会改变。
谁能告诉我为什么吗?我检查了一下,我的BackendService.delete通话成功完成。
我还尝试更改我的自定义挂钩,useBackend如下所示:
import { useCallback } from 'react';
import useSWR, { useSWRConfig, type KeyedMutator } from 'swr';
import BackendService from '@/services/backend';
const useBackend = <D, E = unknown>(path: string | null) => {
const { mutate: globalMutate } = useSWRConfig();
const { data, error, isLoading } = useSWR<D, E>(path, BackendService.get);
const mutator: KeyedMutator<D> = useCallback(
(data, options) => globalMutate(path, data, options),
[path],
);
return {
data,
error,
isLoading,
mutate: mutator,
};
};
export default useBackend;
Run Code Online (Sandbox Code Playgroud)
但它仍然没有帮助(同样的问题)
我也尝试提供revalidate突变:
await getAllSecretsMutate(
async () => {
await BackendService.delete('/user/secrets');
return { secrets: [] };
},
{
optimisticData: { secrets: [] },
rollbackOnError: true,
revalidate: false,
},
);
Run Code Online (Sandbox Code Playgroud)
然后它起作用了——缓存确实改变了。但我导航到其他页面然后返回 - 缓存再次无效。
无论如何,如果添加 revalidate: false 确实会更新缓存,那么我会说,当我使用 revalidate: true (默认)时,一旦异步更新解析,重新验证就会从我的服务器带来非空数据?但就是这样 - 我检查了服务器的响应,它用空数组响应:
另外,我不认为static方法的行为会导致该问题,因为我将其重构BackendService为如下所示:
import { preload } from 'swr';
import type { IHttpMethod, IRefreshTokenRoute } from '@/interfaces/http';
const routesWithRefreshToken: IRefreshTokenRoute[] = [
{ method: 'GET', path: '/user/auth' },
{ method: 'GET', path: '/user/auth/refresh-token' },
];
const fetcher = async <R = unknown, D = unknown>(path: string, method: IHttpMethod, data?: D) => {
const endpointPath = import.meta.env.VITE_BACKEND_URL + path;
const withRefresh = !!routesWithRefreshToken.find(
(route) => route.method === method && route.path === path,
);
const token = (withRefresh ? localStorage : sessionStorage).getItem('token');
const res = await fetch(endpointPath, {
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;
};
const get = <R = unknown>(path: string) => {
return fetcher<R, null>(path, 'GET');
};
const post = <R = unknown, D = unknown>(path: string, data?: D) => {
return fetcher<R, D>(path, 'POST', data);
};
const patch = <R = unknown, D = unknown>(path: string, data?: D) => {
return fetcher<R, D>(path, 'PATCH', data);
};
const deleter = <R = unknown>(path: string) => {
return fetcher<R, null>(path, 'DELETE');
};
const preloader = (path: string) => {
return preload(path, get);
};
const BackendService = {
fetcher,
get,
post,
patch,
deleter,
preloader,
};
export default BackendService;
Run Code Online (Sandbox Code Playgroud)
但这没有帮助。
我通过强制突变解决了这个问题:
import useSWR, { type KeyedMutator } from 'swr';
import { useCallback } from 'react';
import BackendService from '@/services/backend';
const useBackend = <D, E = unknown>(path: string | null) => {
const { data, error, isLoading, mutate } = useSWR<D, E>(path, BackendService.get);
/**
* * Forced mutation is required for synchronization issues,
* * as noted here: /sf/answers/5305757621/
* * The second mutation call uses cache therefore not extra API call network is made
*/
const forcedMutation: KeyedMutator<D> = useCallback(
async (mutationData, options) => {
const data = await mutate(mutationData, options);
await mutate();
return data;
},
[mutate],
);
return { data, error, isLoading, mutate: forcedMutation };
};
export default useBackend;
Run Code Online (Sandbox Code Playgroud)
请阅读评论以了解更多..
| 归档时间: |
|
| 查看次数: |
2154 次 |
| 最近记录: |