-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
POC reproduction of Issue #9204 #9407
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -29,9 +29,12 @@ export function useQuery< | |||
const context = useContext(getApolloContext()); | ||||
const client = useApolloClient(options?.client); | ||||
const defaultWatchQueryOptions = client.defaultOptions.watchQuery; | ||||
const watchQueryOptions = useMemo( | ||||
() => createWatchQueryOptions(query, options, defaultWatchQueryOptions), | ||||
[query, options, defaultWatchQueryOptions] | ||||
) | ||||
verifyDocumentType(query, DocumentType.Query); | ||||
const [obsQuery, setObsQuery] = useState(() => { | ||||
const watchQueryOptions = createWatchQueryOptions(query, options, defaultWatchQueryOptions); | ||||
// See if there is an existing observable that was used to fetch the same | ||||
// data and if so, use it instead since it will contain the proper queryId | ||||
// to fetch the result set. This is used during SSR. | ||||
|
@@ -62,7 +65,7 @@ export function useQuery< | |||
{ | ||||
// The only options which seem to actually be used by the | ||||
// RenderPromises class are query and variables. | ||||
getOptions: () => createWatchQueryOptions(query, options, defaultWatchQueryOptions), | ||||
getOptions: () => watchQueryOptions, | ||||
fetchData: () => new Promise<void>((resolve) => { | ||||
const sub = obsQuery!.subscribe({ | ||||
next(result) { | ||||
|
@@ -108,14 +111,13 @@ export function useQuery< | |||
options, | ||||
result, | ||||
previousData: void 0 as TData | undefined, | ||||
watchQueryOptions: createWatchQueryOptions(query, options, defaultWatchQueryOptions), | ||||
watchQueryOptions, | ||||
}); | ||||
|
||||
// An effect to recreate the obsQuery whenever the client or query changes. | ||||
// This effect is also responsible for checking and updating the obsQuery | ||||
// options whenever they change. | ||||
useEffect(() => { | ||||
const watchQueryOptions = createWatchQueryOptions(query, options, defaultWatchQueryOptions); | ||||
let nextResult: ApolloQueryResult<TData> | undefined; | ||||
if (ref.current.client !== client || !equal(ref.current.query, query)) { | ||||
const obsQuery = client.watchQuery(watchQueryOptions); | ||||
|
@@ -219,8 +221,8 @@ export function useQuery< | |||
return () => subscription.unsubscribe(); | ||||
}, [obsQuery, context.renderPromises, client.disableNetworkFetches]); | ||||
|
||||
let partial: boolean | undefined; | ||||
({ partial, ...result } = result); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have to assume there was a reason for doing this that I don't understand, but it is one of the underlying causes of the loss of identity stability in the return value. The result of the change here is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This got fixed in PR #9459, and now works without rebinding any variables: apollo-client/src/react/hooks/useQuery.ts Line 454 in 3860b1f
|
||||
const partial: boolean | undefined = result.partial; | ||||
delete result.partial | ||||
|
||||
{ | ||||
// BAD BOY CODE BLOCK WHERE WE PUT SIDE-EFFECTS IN THE RENDER FUNCTION | ||||
|
@@ -252,7 +254,7 @@ export function useQuery< | |||
!options?.skip && | ||||
result.loading | ||||
) { | ||||
obsQuery.setOptions(createWatchQueryOptions(query, options, defaultWatchQueryOptions)).catch(() => {}); | ||||
obsQuery.setOptions(watchQueryOptions).catch(() => {}); | ||||
} | ||||
|
||||
// We assign options during rendering as a guard to make sure that | ||||
|
@@ -311,14 +313,15 @@ export function useQuery< | |||
subscribeToMore: obsQuery.subscribeToMore.bind(obsQuery), | ||||
}), [obsQuery]); | ||||
|
||||
return { | ||||
return useMemo(() => ({ | ||||
...obsQueryFields, | ||||
variables: createWatchQueryOptions(query, options, defaultWatchQueryOptions).variables, | ||||
variables: watchQueryOptions.variables, | ||||
client, | ||||
called: true, | ||||
previousData: ref.current.previousData, | ||||
...result, | ||||
}; | ||||
}), [obsQueryFields, watchQueryOptions.variables, client, ref.current.previousData, result]); | ||||
|
||||
} | ||||
|
||||
/** | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One fun bug: this
useMemo
works great as long asoptions
is undefined (justuseQuery(query)
), but as soon as you calluseQuery(query, {...})
with options, that's a fresh object foruseMemo
, sowatchQueryOptions
gets regenerated with everyuseMemo
call.