Skip to content

Instantly share code, notes, and snippets.

@Tahul
Last active January 6, 2021 00:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tahul/21187b566cfef5dfd380d67da44ca65a to your computer and use it in GitHub Desktop.
Save Tahul/21187b566cfef5dfd380d67da44ca65a to your computer and use it in GitHub Desktop.
[React Typed Global Context] A sample of a global context hook written in TypeScript #react #hooks #context #typescript #reducer #action
import React, { Dispatch } from 'react'
import reducer from './b_reducer'
// Typings
export interface ContextDefaultState {
name: string | null
}
// Defaults
export const contextDefaultState: ContextDefaultState = {
name: null
}
// Contexts
// - State
const StateContext = React.createContext<ContextDefaultState | undefined>(undefined)
StateContext.displayName = 'StateContext'
// - Dispatch
const DispatchContext = React.createContext<Dispatch<ContextActionType> | undefined>(undefined)
DispatchContext.displayName = 'DispatchContext'
// Context provider
const ContextProvider = ({ children }: { children: React.ReactNode }) => {
const [state, dispatch] = React.useReducer(reducer, contextDefaultState)
return (
<StateContext.Provider value={state}>
<DispatchContext.Provider value={dispatch}>
{children}
</DispatchContext.Provider>
</StateContext.Provider>
)
}
/**
* useContextState hook
*/
const useContextState = (): ContextDefaultState => {
const context = React.useContext(ContextStateContext)
if (!context) throw new Error('Please us this within the StateProvider')
return context
}
/**
* useContextDispatch hook
*/
const useContextDispatch = (): Dispatch<ActionType> => {
const context = React.useContext(ContextDispatchContext)
if (!context) throw new Error('Please us this within the DispatchProvider')
return context
}
/**
* useContext hook
*/
const useContext = () => {
return [useContextState(), useContextDispatch()]
}
export { ContextProvider, useContextState, useContextDispatch, useContext }
import { ContextDefaultState, contextDefaultState } from './a_context'
// Typings
export interface ContextActionPayload {
name?: string
}
export type ContextActionType = {
type: 'SET_NAME' | 'RESET_NAME'
payload?: ContextActionPayload
}
// Reducer
const ContextReducer = (initialState: ContextDefaultState, action: ContextActionType) => {
switch (action.type) {
case 'SET_NAME':
return {
name: action?.payload?.name || ''
}
case 'RESET_NAME':
return {
name: initialState.name
}
default:
throw new Error(`Unhandled action type: ${action.type}`)
}
}
export default ContextReducer
import { Dispatch } from 'react'
import { ContextActionType, ContextActionPayload } from './b_reducer'
/**
* Set name action.
*
* @param {Dispatch<ContextActionType>} dispatch
* @param { name: string } payload
*/
export const setNameAction = (
dispatch: Dispatch<ContextActionType>,
{ name }: ContextActionPayload,
) => {
dispatch({
type: 'SET_NAME',
payload: { name }
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment