diff --git a/CHANGELOG.md b/CHANGELOG.md index bbb242a5624..54edeff41be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## Apollo Client 3.3.11 + +### Bug fixes + +- Fix `useLazyQuery` `forceUpdate` loop regression introduced by [#7655](https://github.com/apollographql/apollo-client/pull/7655) in version 3.3.10.
+ [@benjamn](https://github.com/benjamn) in [#7715](https://github.com/apollographql/apollo-client/pull/7715) + ## Apollo Client 3.3.10 ### Bug fixes diff --git a/src/react/hooks/utils/useBaseQuery.ts b/src/react/hooks/utils/useBaseQuery.ts index 30823c25698..7052df65fc0 100644 --- a/src/react/hooks/utils/useBaseQuery.ts +++ b/src/react/hooks/utils/useBaseQuery.ts @@ -23,36 +23,31 @@ export function useBaseQuery( const updatedOptions = options ? { ...options, query } : { query }; const queryDataRef = useRef>(); - const queryData = - queryDataRef.current || - new QueryData({ + const queryData = queryDataRef.current || ( + queryDataRef.current = new QueryData({ 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. forceUpdate(); } } - }); + }) + ); queryData.setOptions(updatedOptions); queryData.context = context; - // SSR won't trigger the effect hook below that stores the current - // `QueryData` instance for future renders, so we'll handle that here if - // the current render is happening on the server side. - if (queryData.ssrInitiated() && !queryDataRef.current) { - queryDataRef.current = queryData; - } - // `onError` and `onCompleted` callback functions will not always have a // stable identity, so we'll exclude them from the memoization key to // prevent `afterExecute` from being triggered un-necessarily. @@ -76,12 +71,6 @@ export function useBaseQuery( : (result as QueryResult); useEffect(() => { - // We only need one instance of the `QueryData` class, so we'll store it - // as a ref to make it available on subsequent renders. - if (!queryDataRef.current) { - queryDataRef.current = queryData; - } - return () => queryData.cleanup(); }, []);