Created
August 8, 2021 23:46
-
-
Save 3imed-jaberi/43275ab5495bae2fceb748c0aa40557b to your computer and use it in GitHub Desktop.
useCombineReducer - Helper Hook for React.js
This file contains hidden or 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
| /** | |
| * @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