////// useCustomHook.ts
import { useReducer, useCallback } from 'react';
type State = {
name: string;
isLoading: boolean;
errorMessage?: string;
};
type Handlers = {
onSubmit: (name: State['name']) => void;
};
enum ActionTypes {
OnSubmit = 'on-submit',
OnSuccess = 'on-success',
OnFailure = 'on-failure',
}
type Action =
| { type: ActionTypes.OnSubmit, name: State['name'] }
| { type: ActionTypes.OnSuccess }
| { type: ActionTypes.OnFailure, errorMessage: Required<State['errorMessage']> };
const reducer: React.Reducer<State, Action> = (state: State, action: Action) => {
const patch = (diff: Partial<State>): State => ({ ...state, ...diff });
switch (action.type) {
case ActionTypes.OnSubmit:
return patch({
isLoading: true,
effect: {
cmd: Cmd.hogeHoge, // api叩いたり
args: [action.name],
successActionCreator: () => ({ type: ActionTypes.OnSuccess }),
failureActionCreator: (error: Error) => ({ type: ActionTypes.OnFailure, errorMessage: error.message }),
},
});
case ActionTypes.OnSuccess:
return patch({
isLoading: false,
effect: undefined,
});
case ActionTypes.OnFailure:
return patch({
isLoading: false,
effect: undefined,
errorMessage: action.errorMessage
});
}
};
const createInitialState = (name: State['name']): State => ({
name,
isLoading: false,
});
const useCustomHook = (name: State['name']): [State, Handlers] => {
const [state, dispatch] = useReducer(reducer, name, createInitialState);
const handlers: Handlers = {
onSubmit: useCallback((name) => {
dispatch({ type: ActionTypes.OnSubmit, name });
}, []),
};
return [state, handlers];
};
export default useCustomHook;