Skip to content

AuthContext hooks

Dead-simple AuthContext implementation

React
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

React
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

React
App.tsx
const App: FC = () => {
  const {user} = useAuth();
  return user.token ? <AuthenticatedApp /> : <UnauthenticatedApp />;
};

Requesting resources

TypeScript
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};
};