I have a function called scheduleShortcut
that gets used in a couple places throughout an application. Initially, this function was local to the specific components but since it is being used multiple times, I want to refactor this function into a global function.
At first, I tried to do the following:
const history = useHistory(); const dispatch = useDispatch(); export const scheduleShortcut = (jobId: number) => { dispatch(jobGanttFocus(jobId)); dispatch(focusJobScheduleFilter(jobId)); dispatch(toggleScheduleView('jobs')); history.push('/schedule'); };
However, when I do this, I get an error that says I can’t use useHistory or useDispatch unless they are inside a React component or a custom hook. Then, I tried to convert scheduleShortcut into a custom hook in the following way:
export const useScheduleShortcut = (jobId: number) => { const history = useHistory(); const dispatch = useDispatch(); dispatch(jobGanttFocus(jobId)); dispatch(focusJobScheduleFilter(jobId)); dispatch(toggleScheduleView('jobs')); history.push('/schedule'); };
This allowed me to utilize useDispatch and useHistory. However, when I try to call this function inside the specific components I need it in, I get a similar error. Basically, it says that I cannot use my custom hook (i.e. useScheduleShortcut
) inside a callback.
<Roster jobId={job.id} assignWorkers={canAssignWorker ? handleAssignWorkers : undefined} scheduleShortcut={() => useScheduleShortcut(jobId)} />
Is there a way I can get around these errors and use scheduleShortcut as a recyclable function? Or is this in fact not possible since I am using the hooks?
Advertisement
Answer
Hooks in fact must be called on top level, you are breaking that rule
You could expose(return) a function from hook that could be called as callback afterwards.
i.e.
export const useScheduleShortcut = () => { const history = useHistory() const dispatch = useDispatch() const dispatchScheduleShortcut = (jobId) => { dispatch(jobGanttFocus(jobId)) dispatch(focusJobScheduleFilter(jobId)) dispatch(toggleScheduleView('jobs')) history.push('/schedule') } return { dispatchScheduleShortcut } };
and then use it as
const { dispatchScheduleShortcut } = useScheduleShortcut() return ( <Roster jobId={job.id} assignWorkers={canAssignWorker ? handleAssignWorkers : undefined} scheduleShortcut={() => dispatchScheduleShortcut(jobId)} /> )