Skip to content

Instantly share code, notes, and snippets.

@3imed-jaberi
Created August 8, 2021 23:46
Show Gist options
  • Select an option

  • Save 3imed-jaberi/43275ab5495bae2fceb748c0aa40557b to your computer and use it in GitHub Desktop.

Select an option

Save 3imed-jaberi/43275ab5495bae2fceb748c0aa40557b to your computer and use it in GitHub Desktop.
useCombineReducer - Helper Hook for React.js
/**
* @title useCombineReducers Hook
* @description Custom hook to combine all useReducer hooks for one global state container with
* one dispatch function. Use at top-level and pass dispatch function (and state) down
* via React's Context API with Provider and Consumer/useContext.
*/
// --------------------------- Source Code --------------------------- //
/**
* Work only with React.js 16.8+ <https://reactjs.org/docs/hooks-intro.html>.
* I think, it's work also with Preact.js 10+ <https://preactjs.com/guide/v10/hooks/> (need to test it).
*/
/**
* combine all useReducers hook to one hook with the same behavouir.
*
* @param {object} reducers object composed by useReducers
* @returns [state, dispatch] like useReducer hook.
* @api public
*/
function useCombineReducer(reducers) {
// global state factory.
const state = Object
.keys(reducers)
.reduce((nextState, key) => {
const [state] = reducers[key]
return { ...nextState, [key]: state }
}, {})
// global dispatch function factory.
function dispatch(action) {
return Object
.keys(reducers)
.map(key => {
const dispatch = reducers[key][1]
return dispatch
})
.forEach(dispatch => dispatch(action))
}
// hooks result.
return [state, dispatch]
}
// --------------------------- Test Code --------------------------- //
/**
* Test coded with jest <https://jestjs.io>.
*/
describe('useCombineReducer', () => {
it('returns the global state object with the given substates', () => {
const [state] = useCombineReducer({
a: ['1', () => { }],
b: ['2', () => { }]
})
expect(state).toEqual({ a: '1', b: '2' })
})
it('returns the global dispatch function that calls all child dispatch functions', () => {
const aCallback = jest.fn()
const bCallback = jest.fn()
const [state, dispatch] = useCombineReducer({
a: ['1', aCallback],
b: ['2', bCallback]
})
dispatch({ type: 'ACTION' })
expect(aCallback).toBeCalledTimes(1)
expect(bCallback).toBeCalledTimes(1)
})
})
// --------------------------- Types (TypeScript) --------------------------- //
function useCombineReducer<T, A>(reducers: Record<keyof T, [T[keyof T], React.Dispatch<A>]>): [T, (action: A) => void]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment