Skip to content

Instantly share code, notes, and snippets.

@pjchender
Created July 11, 2021 10:47
Show Gist options
  • Save pjchender/cf67e510e237dfb49ce5831c4a179751 to your computer and use it in GitHub Desktop.
Save pjchender/cf67e510e237dfb49ce5831c4a179751 to your computer and use it in GitHub Desktop.
React Context with useReducer Pattern
// https://kentcdodds.com/blog/how-to-use-react-context-effectively
import { createContext, useContext, useReducer } from 'react';
type StateType = { count: number };
type ActionType = {
type: 'INCREMENT' | 'DECREMENT';
};
interface CountContextType {
state: StateType;
dispatch: (action: ActionType) => void;
}
const CountContext = createContext<CountContextType | undefined>(undefined);
const countReducer = (state: StateType, action: ActionType) => {
switch (action.type) {
case 'INCREMENT': {
return { count: state.count + 1 };
}
case 'DECREMENT': {
return { count: state.count - 1 };
}
default: {
throw new Error(`[count-context] Unhandled action type: ${action.type}`);
}
}
};
const CountProvider = ({ children }: { children: React.ReactNode }) => {
const [state, dispatch] = useReducer(countReducer, { count: 0 });
const value = { state, dispatch };
return (
<CountContext.Provider value={value}>{children}</CountContext.Provider>
);
};
const useCount = () => {
const ctx = useContext(CountContext);
if (ctx === undefined) {
throw new Error('useCount must be used with a CountProvider');
}
return ctx;
};
export { CountProvider, useCount };
// https://kentcdodds.com/blog/how-to-use-react-context-effectively
import { useCount } from './count-context';
const Counter = () => {
const { dispatch, state } = useCount();
return (
<div>
<p>{state.count}</p>
<button
type="button"
onClick={() => {
dispatch({ type: 'DECREMENT' });
}}
>
-
</button>
<button
type="button"
onClick={() => {
dispatch({ type: 'INCREMENT' });
}}
>
+
</button>
</div>
);
};
export default Counter;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment