Skip to content

Instantly share code, notes, and snippets.

@tkrkt
Last active April 2, 2019 08:03
Show Gist options
  • Save tkrkt/259d0b240cd04791ed17223ec19125fb to your computer and use it in GitHub Desktop.
Save tkrkt/259d0b240cd04791ed17223ec19125fb to your computer and use it in GitHub Desktop.
import { useReducer, useCallback, useRef, useLayoutEffect } from "react";
type Thunk<S, A = any> = (
dispatch: ThunkDispatch<S, A>,
getState: () => S
) => void;
type ThunkDispatch<S, A> = (action: A | Thunk<S, A>) => void;
const isThunk = <S, A>(e: any): e is Thunk<S, A> => {
return typeof e === "function";
};
export const useThunk = <S, A = any>(
reducer: React.Reducer<S, A>,
initialValue: S
): [S, ThunkDispatch<S, A>] => {
const [state, dispatch] = useReducer(reducer, initialValue);
const existsRef = useRef(true);
useLayoutEffect(() => () => (existsRef.current = false));
const stateRef = useRef(state);
useLayoutEffect(() => {
stateRef.current = state;
});
const getState = useCallback(() => {
return stateRef.current;
}, []);
const thunkDispatch = useCallback(
(a: A | Thunk<S, A>) => {
if (existsRef.current) {
if (isThunk(a)) {
a(thunkDispatch, getState);
} else {
dispatch(a);
}
}
},
[dispatch]
);
return [state, thunkDispatch];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment