Skip to content

Instantly share code, notes, and snippets.

@nielsbrakel
Last active November 25, 2021 07:47
Show Gist options
  • Save nielsbrakel/dae3c12a437bbba22d6283e813d39cdc to your computer and use it in GitHub Desktop.
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
/* 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>
)
}
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>
)
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