Last active
May 7, 2023 01:16
-
-
Save vhuerta/bcdec174933caec250962d484ddc16b8 to your computer and use it in GitHub Desktop.
Add thunk capabilities to useReducer and integrates with redux dev-tools
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
| // Actions Type Definition | |
| type AsyncActionPending = { | |
| type: "ASYNC_ACTION_PENDING"; | |
| }; | |
| type AsyncActionFulfilled = { | |
| type: "ASYNC_ACTION_FULFILLED"; | |
| }; | |
| type AsyncAction = AsyncActionPending | AsyncActionFulfilled; | |
| // State type definition | |
| type AsyncState = {loading: boolean}; | |
| // Reducer | |
| function reducer( | |
| state: AsyncState, | |
| { type }: AsyncAction | |
| ) { | |
| switch (type) { | |
| case "ASYNC_ACTION_PENDING": | |
| return {...state, loading: true}; | |
| case "ASYNC_ACTION_FULFILLED": | |
| return {...state, loading: false}; | |
| default: | |
| return state; | |
| } | |
| } | |
| const [state, dispatch] = useThunkReducer(reducer, {loading: false}, "async_action"); // <= Will see the state under async_action prop on redux devtools | |
| const asynctAction = () => { | |
| return (dispatch: Dispatch<AsyncAction>, getState: () => AsyncState) => { | |
| console.log(getState()) // <= Get the current state within the action | |
| dispatch({ type: "ASYNC_ACTION_PENDING" }); // Async action started, now loading is true | |
| setInterval(() => dispatch({ type: "ASYNC_ACTION_FULFILLED" }), 3e3); // Complete action after 3 seconds, now loading is false again | |
| }; | |
| }; |
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
| import { useCallback, Reducer, ReducerState, ReducerAction } from "react"; | |
| import { useReducer } from "reinspect"; | |
| export type StateGetter<A extends Reducer<any, any>> = () => ReducerState<A>; | |
| export type DispatchThunk<A extends Reducer<any, any>> = ( | |
| dispatch: (value: ReducerAction<A>) => void, | |
| state: StateGetter<A> | |
| ) => void; | |
| export type DispatcherThunk<A extends Reducer<any, any>> = ( | |
| action: ReducerAction<A> | DispatchThunk<A> | |
| ) => void; | |
| export type ActionOrThunk<A extends Reducer<any, any>> = | |
| | ReducerAction<A> | |
| | DispatchThunk<A>; | |
| function isDispatchThunk<R extends Reducer<any, any>>( | |
| action: ReducerAction<R> | DispatchThunk<R> | |
| ): action is DispatchThunk<R> { | |
| return typeof action === "function"; | |
| } | |
| /** | |
| * Augments React's useReducer() hook so that the action | |
| * dispatcher supports thunks. | |
| */ | |
| export function useThunkReducer<R extends Reducer<any, any>>( | |
| reducer: R, | |
| initialState: ReducerState<R>, | |
| id: string | |
| ): [ReducerState<R>, DispatcherThunk<R>] { | |
| const [state, dispatch] = useReducer( | |
| reducer, | |
| initialState, | |
| state => state, | |
| id | |
| ); | |
| const getState = useCallback(() => state, [state]); | |
| const dispatchThunk = (action: ActionOrThunk<R>): void => { | |
| return isDispatchThunk(action) | |
| ? action(dispatch, getState) | |
| : dispatch(action); | |
| }; | |
| return [state, dispatchThunk]; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment