AuthContext.tsx
import {AxiosInstance, AxiosRequestConfig} from 'axios';
import {
createContext,
FC,
useCallback,
useContext,
useMemo,
useState,
} from 'react';
import {queryCache} from 'react-query';
import createClient from '../utils/apiClient';
import {getAccessToken} from '../utils/authService';
import {getToken, removeToken, setToken} from '../utils/jwtTokenUtils';
type User {
token?: string;
}
type AuthContextProps {
user: User;
signIn: (token) => void;
signOut: () => void;
}
const AuthContext = createContext({} as IAuthContext);
const AuthProvider: FC = (props) => {
const [user, setUser] = useState<IUser>(() => {
const token = getToken();
return {token};
});
const signIn = useCallback(async () => {
// implement this
}, [setUser]);
const signOut = useCallback(() => {
queryCache.clear();
removeToken();
setUser({});
}, [setUser]);
const value = useMemo(
() => ({user, signIn, signOut}),
[signIn, signOut, user]
);
return <AuthContext.Provider value={value} {...props} />;
};
const useAuth = (): AuthContextProps => {
const context = useContext(AuthContext);
return context;
};
const useClient = (): AxiosInstance => {
const {user, signOut} = useAuth();
const token = user?.token;
const client = useMemo(
() => createClient({authToken: token, onUnauthorized: signOut}),
[token]
);
return useCallback((config: AxiosRequestConfig) => client(config), []);
};
export {AuthProvider, useAuth, useClient};
Adding wrappers
Root.tsx
const AppProviders: FC = ({children}) => {
return (
<StrictMode>
<ChakraProvider>
<ReactQueryConfigProvider config={queryConfig}>
<BrowserRouter>
<AuthProvider>{children}</AuthProvider>
</BrowserRouter>
</ReactQueryConfigProvider>
</ChakraProvider>
</StrictMode>
);
};
const Root: FC = () => {
return (
<AppProviders>
<App />
</AppProviders>
);
};
Simple fork
App.tsx
const App: FC = () => {
const {user} = useAuth();
return user.token ? <AuthenticatedApp /> : <UnauthenticatedApp />;
};
Requesting resources
useGetAllHabitsQuery.ts
// using `useClient`
const useGetAllHabitsQuery = (): {status: QueryStatus; data: unknown} => {
const client = useClient();
const request = useCallback((key) => {
return client({url: 'v1/habits', cancelToken: getCancelToken(key)});
}, []);
const {data, status} = useQuery({queryKey, queryFn: request});
return {data, status};
};