Skip to content

Instantly share code, notes, and snippets.

@kentcdodds
Created May 8, 2019 16:27
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save kentcdodds/5b0e5fba0c2434bdf0029c1d3a3446a5 to your computer and use it in GitHub Desktop.
Save kentcdodds/5b0e5fba0c2434bdf0029c1d3a3446a5 to your computer and use it in GitHub Desktop.
Just some fun idea I had and don't want to lose.
// src/count-context.js
import React from 'react'
function countReducer(count, action) {
const {step = 1} = action
switch (action.type) {
case 'INCREMENT': {
return count + step
}
default: {
throw new Error(`Unsupported action type: ${action.type}`)
}
}
}
const {
ReducerProvider: CountProvider,
useReducerState: useCountState,
useReducerDispatch: useCountDispatch,
} = createReducerContext('Count', countReducer, 0)
function createReducerContext(name, reducer, initialState, init) {
const StateContext = React.createContext()
StateContext.Provider.displayName = `${name}StateProvider`
const DispatchContext = React.createContext()
DispatchContext.Provider.displayName = `${name}DispatchProvider`
function ReducerProvider({children, stateValue, dispatchValue}) {
const [state, dispatch] = React.useReducer(reducer, initialState, init)
return (
<StateContext.Provider value={stateValue || state}>
<DispatchContext.Provider value={dispatchValue || dispatch}>
{children}
</DispatchContext.Provider>
</StateContext.Provider>
)
}
ReducerProvider.displayName = `${name}Provider`
function useReducerState() {
const context = React.useContext(StateContext)
if (context === undefined) {
throw new Error(
`${useReducerState.displayName} must be used within a ${
ReducerProvider.displayName
}`,
)
}
return context
}
useReducerState.displayName = `use${name}State`
function useReducerDispatch() {
const context = React.useContext(DispatchContext)
if (context === undefined) {
throw new Error(
`${useReducerDispatch.displayName} must be used within a ${
ReducerProvider.displayName
}`,
)
}
return context
}
useReducerDispatch.displayName = `use${name}Dispatch`
return {
ReducerProvider,
useReducerState,
useReducerDispatch,
}
}
// export {CountProvider, useCount}
// some-other-file.js
// import {CountProvider, useCount} from './count-context'
function CountDisplay() {
const count = useCountState()
return <div>{`The current count is ${count}`}</div>
}
function Counter() {
const dispatch = useCountDispatch()
return (
<button onClick={() => dispatch({type: 'INCREMENT', step: 2})}>
Increment count
</button>
)
}
function Usage() {
return (
<CountProvider>
<CountDisplay />
<Counter />
</CountProvider>
)
}
export default Usage
@httpJunkie
Copy link

This is interesting! I love finding out about all the cools ways to use Hooks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment