Created
May 8, 2019 16:27
-
-
Save kentcdodds/5b0e5fba0c2434bdf0029c1d3a3446a5 to your computer and use it in GitHub Desktop.
Just some fun idea I had and don't want to lose.
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
// 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is interesting! I love finding out about all the cools ways to use Hooks!