Last active
November 25, 2021 07:47
-
-
Save nielsbrakel/dae3c12a437bbba22d6283e813d39cdc to your computer and use it in GitHub Desktop.
React global provider system using context and hooks to easily manage small application state
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ | |
import { createContext, useContext } from 'react' | |
import { useAuth } from 'GenericOAuthProvidert' | |
type AuthenticationContextType = { | |
login: () => void | |
logout: () => void | |
} | |
const AuthenticationContext = | |
createContext<AuthenticationContextType>(undefined) | |
/** | |
* Use this hook to access the login and logout functions | |
* @example const { login, logout } = useAuthentication() | |
*/ | |
export const useAuthentication = (): any => useContext(AuthenticationContext) | |
/** | |
* This provider is used to give all the child's access to the useAuthentication hook that can be used | |
* to login or logout an user. By managing them in one provider we are able to keep is maintainable. | |
*/ | |
export const AuthenticationProvider = ({ children }: any): JSX.Element => { | |
const { auth } = useAuth() | |
const login = () => { | |
auth.signInWithRedirect() | |
} | |
const logout = async (): Promise<void> => { | |
await auth.signOut({ | |
postLogoutRedirectUri: window.location.origin + '/logout', | |
}) | |
} | |
return ( | |
<AuthenticationContext.Provider value={{ login, logout }}> | |
{children} | |
</AuthenticationContext.Provider> | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import { AuthenticationProvider } from './AuthenticationProvider' | |
import { UserProvider } from './UserProvider' | |
/** | |
* This provider is the place to include all the providers that you want the application to have access | |
* to globally, for this to work it needs to be the first child of your router. Keep in mind the order of the providers | |
* is important since some providers depend on each other. | |
*/ | |
export const GlobalProvider = ({ children }: any): JSX.Element => ( | |
<AuthenticationProvider> | |
<UserProvider> | |
{children} | |
</UserProvider> | |
</AuthenticationProvider> | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { createContext, useContext, useEffect, useState } from 'react' | |
import { useAuth } from 'GenericOAuthProvider' | |
export interface IUser { | |
name: string | |
email: string | |
accessToken: string | |
isAuthenticated: boolean | |
isManager: boolean | |
} | |
const initialUser: IUser = { | |
name: '', | |
email: '', | |
accessToken: '', | |
isAuthenticated: false, | |
isManager: false, | |
} | |
const UserContext = createContext<IUser>(initialUser) | |
/** | |
* Use this hook to get all the needed info about the user | |
* @example const user = useUser() | |
*/ | |
export const useUser = (): IUser => useContext(UserContext) | |
/** | |
* This provider is used to give all the child's access to the useUser hook that can be used | |
* to access all information of an user. By using this pattern we are able to make the hook a singleton | |
* what greatly improves performance and maintainability. | |
*/ | |
export const UserProvider = ({ children }: any): JSX.Element => { | |
const { accessToken } = useAuth() | |
const [user, setUser] = useState<IUser>(initialUser) | |
const update = (): void => { | |
const claims = accessToken.idToken.claims | |
const updatedUser: IUser = { | |
name: claims.name, | |
email: claims.email, | |
accessToken, | |
isAuthenticated: true, | |
isManager: claims.isManager, | |
} | |
setUser(updatedUser) | |
} | |
useEffect(() => { | |
if (accessToken.isAuthenticated) { | |
update() | |
} else { | |
setUser(initialUser) | |
} | |
}, [accessToken]) | |
return <UserContext.Provider value={user}>{children}</UserContext.Provider> | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment