@@ -12,7 +12,7 @@ import { useApolloClient } from "./useApolloClient.js";
12
12
import { useSyncExternalStore } from "./useSyncExternalStore.js" ;
13
13
import type { ApolloClient , OperationVariables } from "../../core/index.js" ;
14
14
import type { NoInfer } from "../types/types.js" ;
15
- import { useDeepMemo , useLazyRef , wrapHook } from "./internal/index.js" ;
15
+ import { useDeepMemo , wrapHook } from "./internal/index.js" ;
16
16
import equal from "@wry/equality" ;
17
17
18
18
export interface UseFragmentOptions < TData , TVars >
@@ -64,47 +64,53 @@ function _useFragment<TData = any, TVars = OperationVariables>(
64
64
options : UseFragmentOptions < TData , TVars >
65
65
) : UseFragmentResult < TData > {
66
66
const { cache } = useApolloClient ( options . client ) ;
67
+ const { from, ...rest } = options ;
67
68
68
- const diffOptions = useDeepMemo < Cache . DiffOptions < TData , TVars > > ( ( ) => {
69
- const {
70
- fragment,
71
- fragmentName,
72
- from,
73
- optimistic = true ,
74
- ...rest
75
- } = options ;
76
-
77
- return {
78
- ...rest ,
79
- returnPartialData : true ,
80
- id : typeof from === "string" ? from : cache . identify ( from ) ,
81
- query : cache [ "getFragmentDoc" ] ( fragment , fragmentName ) ,
82
- optimistic,
83
- } ;
84
- } , [ options ] ) ;
85
-
86
- const resultRef = useLazyRef < UseFragmentResult < TData > > ( ( ) =>
87
- diffToResult ( cache . diff < TData > ( diffOptions ) )
69
+ // We calculate the cache id seperately from `stableOptions` because we don't
70
+ // want changes to non key fields in the `from` property to affect
71
+ // `stableOptions` and retrigger our subscription. If the cache identifier
72
+ // stays the same between renders, we want to reuse the existing subscription.
73
+ const id = React . useMemo (
74
+ ( ) => ( typeof from === "string" ? from : cache . identify ( from ) ) ,
75
+ [ cache , from ]
88
76
) ;
89
77
90
- const stableOptions = useDeepMemo ( ( ) => options , [ options ] ) ;
78
+ const resultRef = React . useRef < UseFragmentResult < TData > > ( ) ;
79
+ const stableOptions = useDeepMemo ( ( ) => ( { ...rest , from : id ! } ) , [ rest , id ] ) ;
91
80
92
81
// Since .next is async, we need to make sure that we
93
82
// get the correct diff on the next render given new diffOptions
94
- React . useMemo ( ( ) => {
95
- resultRef . current = diffToResult ( cache . diff < TData > ( diffOptions ) ) ;
96
- } , [ diffOptions , cache ] ) ;
83
+ const currentDiff = React . useMemo ( ( ) => {
84
+ const { fragment, fragmentName, from, optimistic = true } = stableOptions ;
85
+
86
+ return diffToResult (
87
+ cache . diff < TData > ( {
88
+ ...stableOptions ,
89
+ returnPartialData : true ,
90
+ id : from ,
91
+ query : cache [ "getFragmentDoc" ] ( fragment , fragmentName ) ,
92
+ optimistic,
93
+ } )
94
+ ) ;
95
+ } , [ stableOptions , cache ] ) ;
97
96
98
97
// Used for both getSnapshot and getServerSnapshot
99
- const getSnapshot = React . useCallback ( ( ) => resultRef . current , [ ] ) ;
98
+ const getSnapshot = React . useCallback (
99
+ ( ) => resultRef . current || currentDiff ,
100
+ [ currentDiff ]
101
+ ) ;
100
102
101
103
return useSyncExternalStore (
102
104
React . useCallback (
103
105
( forceUpdate ) => {
104
106
let lastTimeout = 0 ;
105
107
const subscription = cache . watchFragment ( stableOptions ) . subscribe ( {
106
108
next : ( result ) => {
107
- if ( equal ( result , resultRef . current ) ) return ;
109
+ // Since `next` is called async by zen-observable, we want to avoid
110
+ // unnecessarily rerendering this hook for the initial result
111
+ // emitted from watchFragment which should be equal to
112
+ // `currentDiff`.
113
+ if ( equal ( result , currentDiff ) ) return ;
108
114
resultRef . current = result ;
109
115
// If we get another update before we've re-rendered, bail out of
110
116
// the update and try again. This ensures that the relative timing
@@ -115,11 +121,12 @@ function _useFragment<TData = any, TVars = OperationVariables>(
115
121
} ,
116
122
} ) ;
117
123
return ( ) => {
124
+ resultRef . current = void 0 ;
118
125
subscription . unsubscribe ( ) ;
119
126
clearTimeout ( lastTimeout ) ;
120
127
} ;
121
128
} ,
122
- [ cache , stableOptions ]
129
+ [ cache , stableOptions , currentDiff ]
123
130
) ,
124
131
getSnapshot ,
125
132
getSnapshot
0 commit comments