Skip to content

Commit

Permalink
Fix useLazyQuery forceUpdate loop regression.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
benjamn committed Feb 15, 2021
1 parent 2b1f1f4 commit d3735a9
Showing 1 changed file with 5 additions and 3 deletions.
8 changes: 5 additions & 3 deletions src/react/hooks/utils/useBaseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ export function useBaseQuery<TData = any, TVariables = OperationVariables>(
options: updatedOptions as QueryDataOptions<TData, TVariables>,
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.
Expand Down

0 comments on commit d3735a9

Please sign in to comment.