Skip to content

Instantly share code, notes, and snippets.

@tomhicks
Created January 11, 2021 11:41
Show Gist options
  • Save tomhicks/95d455186fadda2f7d99e6163aa9d360 to your computer and use it in GitHub Desktop.
Save tomhicks/95d455186fadda2f7d99e6163aa9d360 to your computer and use it in GitHub Desktop.
React Hook for queueing and processing async tasks sequentially
function useTaskQueue(params: {
shouldProcess: boolean
}): {
tasks: ReadonlyArray<Task>
isProcessing: boolean
addTask: (task: Task) => void
} {
const [queue, setQueue] = React.useState<{
isProcessing: boolean
tasks: Array<Task>
}>({isProcessing: false, tasks: []})
React.useEffect(() => {
if (!params.shouldProcess) return
if (queue.tasks.length === 0) return
if (queue.isProcessing) return
const task = queue.tasks[0]
setQueue((prev) => ({
isProcessing: true,
tasks: prev.tasks.slice(1),
}))
Promise.resolve(task()).finally(() => {
setQueue((prev) => ({
isProcessing: false,
tasks: prev.tasks,
}))
})
}, [queue, params.shouldProcess])
return {
tasks: queue.tasks,
isProcessing: queue.isProcessing,
addTask: React.useCallback((task) => {
setQueue((prev) => ({
isProcessing: prev.isProcessing,
tasks: [...prev.tasks, task],
}))
}, []),
}
}
type Task = () => Promise<void> | void
@sladkoff
Copy link

Hi @majames, I just double-checked this in my codebase. I noticed that I can remove the flushSync(...) now and the original problem is not reproducible.

However, I was able to reproduce the problem on the code revision from a year ago... It could indeed be fixed by applying the flushSync(...) wrapper... It doesn't make a lot of sense to me. I'm assuming it has something to do with the context of my code and maybe some dependency constellation 🤷

You're probably right that this is not the correct way to do this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment