Feat(frontend): React Query for interacting with the backend

This commit is contained in:
2023-09-04 16:08:44 -04:00
parent 36fadc059a
commit 1f7066a2d9
4 changed files with 175 additions and 14 deletions

View File

@@ -1,6 +1,8 @@
import React from "react";
import "./App.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
// Roboto font and its weights
import "@fontsource/roboto/300.css";
import "@fontsource/roboto/400.css";
@@ -22,21 +24,25 @@ import { AuthContextProvider } from "./AuthContext";
// React router
import Router from "./Router";
function App() {
const queryClient = new QueryClient();
const App = () => {
return (
<AuthContextProvider>
<HelmetProvider>
<Helmet>
<title>Todo</title>
</Helmet>
<ThemeProvider>
<Container maxWidth="md">
<Router />
</Container>
</ThemeProvider>
</HelmetProvider>
</AuthContextProvider>
<QueryClientProvider client={queryClient}>
<AuthContextProvider>
<HelmetProvider>
<Helmet>
<title>Todo</title>
</Helmet>
<ThemeProvider>
<Container maxWidth="md">
<Router />
</Container>
</ThemeProvider>
</HelmetProvider>
</AuthContextProvider>
</QueryClientProvider>
);
}
};
export default App;

80
frontend/src/query.ts Normal file
View File

@@ -0,0 +1,80 @@
import axios, { AxiosError } from "axios";
import { useContext } from "react";
import {
MutationFunction,
QueryFunction,
QueryFunctionContext,
QueryKey,
useMutation as useReactMutation,
UseMutationOptions,
UseMutationResult,
useQuery as useReactQuery,
UseQueryOptions,
UseQueryResult,
} from "@tanstack/react-query";
import { AuthContext } from "src/AuthContext";
const MAX_FAILURES = 2;
export function useQuery<
TQueryFnData = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey,
>(
queryKey: TQueryKey,
queryFn: QueryFunction<TQueryFnData, TQueryKey>,
options?: UseQueryOptions<TQueryFnData, AxiosError, TData, TQueryKey>,
): UseQueryResult<TData, AxiosError> {
const { setAuthenticated } = useContext(AuthContext);
return useReactQuery<TQueryFnData, AxiosError, TData, TQueryKey>(
queryKey,
async (context: QueryFunctionContext<TQueryKey>) => {
try {
return await queryFn(context);
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 401) {
setAuthenticated(false);
}
throw error;
}
},
{
retry: (failureCount: number, error: AxiosError) =>
failureCount < MAX_FAILURES &&
(!error.response || error.response.status >= 500),
...options,
},
);
}
export function useMutation<
TData = unknown,
TVariables = void,
TContext = unknown,
>(
mutationFn: MutationFunction<TData, TVariables>,
options?: UseMutationOptions<TData, AxiosError, TVariables, TContext>,
): UseMutationResult<TData, AxiosError, TVariables, TContext> {
const { setAuthenticated } = useContext(AuthContext);
return useReactMutation<TData, AxiosError, TVariables, TContext>(
async (variables: TVariables) => {
try {
return await mutationFn(variables);
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 401) {
setAuthenticated(false);
}
throw error;
}
},
{
retry: (failureCount: number, error: AxiosError) =>
failureCount < MAX_FAILURES &&
(!error.response || error.response.status >= 500),
...options,
},
);
}