From abb51b98eb07d0f798e0ccc8e9809812df6452f3 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Thu, 2 Jan 2025 15:08:38 -0500 Subject: [PATCH] fix(ui): properly instantiates abort controllers (#10309) Fixes #10296. When an async `useEffect` runs twice or more before resolving, we use the Abort Controller API to cancel previous events. This works by instantiating a new ref on each run, and if a previous ref was detected, it will be aborted and a new instance will be set up for the next run. However, while the logic was aborting previous instances as expected, it was failing to instantiate a new one. --- packages/ui/src/utilities/abortAndIgnore.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/ui/src/utilities/abortAndIgnore.ts b/packages/ui/src/utilities/abortAndIgnore.ts index 721afdb647..4895bf9c0b 100644 --- a/packages/ui/src/utilities/abortAndIgnore.ts +++ b/packages/ui/src/utilities/abortAndIgnore.ts @@ -8,19 +8,28 @@ export function abortAndIgnore(abortController: AbortController) { } } +/** + * Use this function when an effect is triggered multiple times over and you want to cancel the previous effect. + * It will abort the previous effect and create a new AbortController for the next effect. + * Important: You must also _reset_ the `abortControllerRef` after the effect is done, otherwise the next effect will be aborted immediately. + * For example, run `abortControllerRef.current = null` in a `finally` block or after an awaited promise. + * @param abortControllerRef + * @returns {AbortController} + */ export function handleAbortRef( abortControllerRef: React.RefObject, ): AbortController { + const newController = new AbortController() + if (abortControllerRef.current) { try { abortControllerRef.current.abort() - abortControllerRef.current = null } catch (_err) { // swallow error } - } else { - const controller = new AbortController() - abortControllerRef.current = controller - return controller } + + abortControllerRef.current = newController + + return newController }