Skip to content

Instantly share code, notes, and snippets.

@felippepuhle
Created September 10, 2020 18:56
Show Gist options
  • Save felippepuhle/c1a6d55c6204eee8f0f1bb7027afc5c2 to your computer and use it in GitHub Desktop.
Save felippepuhle/c1a6d55c6204eee8f0f1bb7027afc5c2 to your computer and use it in GitHub Desktop.
import {useCallback, useReducer, useEffect, Reducer} from 'react';
type GenericDataType = {
id: string;
};
type Action<T extends GenericDataType> = {
type: 'PROCESS_ROW';
payload: T;
};
type State<T extends GenericDataType> = {
queue: T[];
list: T[];
};
type Params<T extends GenericDataType> = {
initialList: T[];
processRow: (data: T) => Promise<T>;
};
const useAsyncQueue = <T extends GenericDataType>({
initialList,
processRow,
}: Params<T>): State<T> => {
const reducer: Reducer<State<T>, Action<T>> = useCallback((state, action) => {
switch (action.type) {
case 'PROCESS_ROW':
return {
...state,
queue: state.queue.filter((row) => row.id !== action.payload.id),
list: state.list.map((row) => {
if (row.id !== action.payload.id) {
return row;
}
return action.payload;
}),
};
default:
return state;
}
}, []);
const [state, dispatch] = useReducer(reducer, {
queue: initialList,
list: initialList,
});
const processQueue = useCallback(async () => {
if (state.queue.length === 0) {
return;
}
const row = state.queue[0];
const payload = await processRow(row);
dispatch({
type: 'PROCESS_ROW',
payload,
});
}, [processRow, state.queue, dispatch]);
useEffect(() => {
processQueue();
}, [processQueue]);
return state;
};
export default useAsyncQueue;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment