Zyzle.dev
;

React Context and Hook

15th April, 2023

Although I use this all the time I always have to look up how to implement it. This example is based on Kent C. Dodds’ article1 on the subject.

I’ve used this most recently when creating the Storypoint Shuffle2 app.

context.ts
import * as React from 'react'
type Action = {type: 'increment'} | {type: 'decrement'}
type Dispatch = (action: Action) => void
type State = {count: number}
type CountProviderProps = {children: React.ReactNode}
const CountStateContext = React.createContext<
{state: State; dispatch: Dispatch} | undefined
>(undefined)
function countReducer(state: State, action: Action) {
switch (action.type) {
case 'increment': {
return {count: state.count + 1}
}
default: {
throw new Error(`Unhandled action type: ${action.type}`)
}
}
}
function CountProvider({children}: CountProviderProps) {
const [state, dispatch] = React.useReducer(countReducer, {count: 0})
// NOTE: you *might* need to memoize this value
// Learn more in http://kcd.im/optimize-context
const value = {state, dispatch}
return (
<CountStateContext.Provider value={value}>
{children}
</CountStateContext.Provider>
)
}
function useCount() {
const context = React.useContext(CountStateContext)
if (context === undefined) {
throw new Error('useCount must be used within a CountProvider')
}
return context
}
export {CountProvider, useCount}

The provider can then be used to wrap the rest of your app:

<CountProvider>
<ChildComponents />
</CountProvider>

And in your components that need the context:

const {state, dispatch} = useCount();

Footnotes

  1. Kent C. Dodds - React Context

  2. Storypoint Shuffle on Github