Skip to content

Commit

Permalink
feat: 新增 axios 和 react-query 的封装
Browse files Browse the repository at this point in the history
feat: 新增菜单模块的业务 api 访问 hooks,以及全局 antd 的 message
  • Loading branch information
kangood committed Feb 17, 2024
1 parent 8482f00 commit ce52387
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 23 deletions.
67 changes: 67 additions & 0 deletions src/http/axios/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import axios from 'axios';

import { globalError } from '@/utils/antd-extract';
import { useUserToken } from '@/store/userStore';

// 刷新token的API调用
// const refreshTokenApi = async () => {
// // 调用API
// const res = await service.get('auth/refresh', {
// params: {
// refreshToken: localStorage.getItem('refresh_token'),
// },
// });
// if (res) {
// // 更新token数据
// FetcherStore.setState((state) => {
// state.token = res.data.accessToken;
// });
// localStorage.setItem('refresh_token', res.data.refreshToken);
// }
// return res;
// };
// 设置axios的额外配置
export const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
});
// 拦截请求处理
service.interceptors.request.use(async (params) => {
// 添加token
const userToken = useUserToken();
if (userToken.accessToken) {
params.headers.set('Authorization', `Bearer ${userToken.accessToken}`);
}
return params;
});
// 拦截响应处理
service.interceptors.response.use(
async (response) => {
return response;
},
async (error) => {
// if (import.meta.env.DEV) console.log('respError', error);
if (!error.response)
switch (error.response.status) {
case 401: {
// 如果响应401就把原本的FetcherStore数据设置为空,好让页面跳至登录页
// FetcherStore.setState((state) => {
// state.token = null;
// });
// // 响应401且不是刷新token的请求时,去主动调用刷新token请求
// if (!error.response.config.url.includes('auth/refresh')) {
// const res = await refreshTokenApi();
// if (res.status === 200) {
// return axios(error.response.config);
// }
// message.error('登录过期,请重新登录');
// return Promise.reject(res.data);
// }
break;
}
default:
globalError(error);
break;
}
return Promise.reject(error);
},
);
16 changes: 16 additions & 0 deletions src/http/tanstack/react-query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { QueryClient } from '@tanstack/react-query';

// 创建一个 client
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
// 设置HTTP状态码为403的时候不重试,其他情况取默认值
retry: (_failureCount, error: any) => error.response?.status !== 403,
cacheTime: 300_000, // 缓存有效期 5m
staleTime: 10_1000, // 数据变得 "陈旧"(stale)的时间 10s
refetchOnWindowFocus: false, // 禁止窗口聚焦时重新获取数据
refetchOnReconnect: false, // 禁止重新连接时重新获取数据
refetchOnMount: false, // 禁止组件挂载时重新获取数据
},
},
});
33 changes: 10 additions & 23 deletions src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// react-query
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
// react
import { Suspense } from 'react';
Expand All @@ -10,6 +10,7 @@ import { HelmetProvider } from 'react-helmet-async';
import 'virtual:svg-icons-register';

import App from '@/App';
import { queryClient } from '@/http/tanstack/react-query';

// i18n
import './locales/i18n';
Expand All @@ -26,31 +27,17 @@ const charAt = `
`;
console.info(`%c${charAt}`, 'color: #5BE49B');

// 创建一个 client
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 3, // 失败重试次数
cacheTime: 300_000, // 缓存有效期 5m
staleTime: 10_1000, // 数据变得 "陈旧"(stale)的时间 10s
refetchOnWindowFocus: false, // 禁止窗口聚焦时重新获取数据
refetchOnReconnect: false, // 禁止重新连接时重新获取数据
refetchOnMount: false, // 禁止组件挂载时重新获取数据
},
},
});

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);

root.render(
<HelmetProvider>
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools initialIsOpen={false} />
<Suspense>
<App />
</Suspense>
</QueryClientProvider>
</HelmetProvider>,
<HelmetProvider>
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools initialIsOpen={false} />
<Suspense>
<App />
</Suspense>
</QueryClientProvider>
</HelmetProvider>,
);

// 不再使用 mock 数据,调用 nest 后端获取
Expand Down
60 changes: 60 additions & 0 deletions src/services/menu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useMutation, useQuery } from '@tanstack/react-query';

import { InputType, OutputType } from '@/pages/setting/menus/list.page';

Check failure on line 3 in src/services/menu.ts

View workflow job for this annotation

GitHub Actions / build-and-deploy (16.x)

Cannot find module '@/pages/setting/menus/list.page' or its corresponding type declarations.
import { globalSuccess } from '@/utils/antd-extract';
import { service } from '@/http/axios/service';
import { queryClient } from '@/http/tanstack/react-query';

/**
* 树结构查询
*/
export const useListMenuTree = () => {
return useQuery<OutputType[]>(['listMenuTree'], async () =>
service.get('menu/tree').then((res) => res.data),
);
};

/**
* 树结构查询:给角色模块提供,用于数据隔离
*/
export const useListMenuTreeForRole = () => {
return useQuery<OutputType[]>(['listMenuTreeForRole'], async () =>
service.get('menu/tree').then((res) => res.data),
);
};

/**
* 更新
*/
export const useUpdateMenu = () => {
return useMutation(async (params: InputType) => service.patch('/menu', { ...params }), {
onSuccess: () => {
globalSuccess();
queryClient.invalidateQueries(['listMenuTree']);
},
});
};

/**
* 新建
*/
export const useCreateMenu = () => {
return useMutation(async (params: InputType) => service.post('/menu', { ...params }), {
onSuccess: () => {
globalSuccess();
queryClient.invalidateQueries(['listMenuTree']);
},
});
};

/**
* 删除
*/
export const useDeleteMenu = () => {
return useMutation(async (ids: number[]) => service.delete('/menu', { data: { ids } }), {
onSuccess: () => {
globalSuccess();
queryClient.invalidateQueries(['listMenuTree']);
},
});
};
9 changes: 9 additions & 0 deletions src/utils/antd-extract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { message } from 'antd';
import { AxiosError } from 'axios';

import { Result } from '#/api';

export const globalSuccess = () => message.success('success', 2);
// export const globalError = (error: AxiosError) => message.error(error.message);
export const globalError = (error: AxiosError<Result>) =>
message.error(error.response?.data.message ?? error.message);

0 comments on commit ce52387

Please sign in to comment.