From d3735a918c320ec3a167dd8805e3c66f72bed9d0 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 15 Feb 2021 11:30:07 -0500 Subject: [PATCH] Fix useLazyQuery forceUpdate loop regression. PR #7655 changed this code so that the Promise.resolve().then(forceUpdate) branch was not taken when queryDataRef.current was falsy, so forceUpdate() was called immediately instead (the else branch). As #7713 demonstrates, the Promise delay is important to avoid calling forceUpdate() synchronously during the initial render, which can lead to an infinite rendering loop. To preserve the intent of #7655, we now do the queryDataRef.current check inside the Promise callback, since the component could have been unmounted before the callback fired. --- src/react/hooks/utils/useBaseQuery.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/react/hooks/utils/useBaseQuery.ts b/src/react/hooks/utils/useBaseQuery.ts index 30823c25698..a2d913403a5 100644 --- a/src/react/hooks/utils/useBaseQuery.ts +++ b/src/react/hooks/utils/useBaseQuery.ts @@ -29,12 +29,14 @@ export function useBaseQuery( options: updatedOptions as QueryDataOptions, context, onNewData() { - if (!queryData.ssrInitiated() && queryDataRef.current) { + if (!queryData.ssrInitiated()) { // When new data is received from the `QueryData` object, we want to // force a re-render to make sure the new data is displayed. We can't // force that re-render if we're already rendering however so to be - // safe we'll trigger the re-render in a microtask. - Promise.resolve().then(forceUpdate); + // safe we'll trigger the re-render in a microtask. In case the + // component gets unmounted before this callback fires, we re-check + // queryDataRef.current before calling forceUpdate(). + Promise.resolve().then(() => queryDataRef.current && forceUpdate()); } else { // If we're rendering on the server side we can force an update at // any point.