houdini-react 2.0.0-next.40 → 2.0.0-next.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -8
- package/postInstall.js +1 -1
- package/runtime/hooks/useFragmentHandle.ts +21 -34
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "houdini-react",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.41",
|
|
4
4
|
"description": "The React plugin for houdini",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -81,13 +81,13 @@
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"optionalDependencies": {
|
|
84
|
-
"houdini-react-darwin-x64": "2.0.0-next.
|
|
85
|
-
"houdini-react-darwin-arm64": "2.0.0-next.
|
|
86
|
-
"houdini-react-linux-x64": "2.0.0-next.
|
|
87
|
-
"houdini-react-linux-arm64": "2.0.0-next.
|
|
88
|
-
"houdini-react-win32-x64": "2.0.0-next.
|
|
89
|
-
"houdini-react-win32-arm64": "2.0.0-next.
|
|
90
|
-
"houdini-react-wasm": "2.0.0-next.
|
|
84
|
+
"houdini-react-darwin-x64": "2.0.0-next.41",
|
|
85
|
+
"houdini-react-darwin-arm64": "2.0.0-next.41",
|
|
86
|
+
"houdini-react-linux-x64": "2.0.0-next.41",
|
|
87
|
+
"houdini-react-linux-arm64": "2.0.0-next.41",
|
|
88
|
+
"houdini-react-win32-x64": "2.0.0-next.41",
|
|
89
|
+
"houdini-react-win32-arm64": "2.0.0-next.41",
|
|
90
|
+
"houdini-react-wasm": "2.0.0-next.41"
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
93
|
"compile": "scripts build-go",
|
package/postInstall.js
CHANGED
|
@@ -5,7 +5,7 @@ const https = require('https')
|
|
|
5
5
|
const child_process = require('child_process')
|
|
6
6
|
|
|
7
7
|
// Adjust the version you want to install. You can also make this dynamic.
|
|
8
|
-
const BINARY_DISTRIBUTION_VERSION = '2.0.0-next.
|
|
8
|
+
const BINARY_DISTRIBUTION_VERSION = '2.0.0-next.41'
|
|
9
9
|
|
|
10
10
|
// Windows binaries end with .exe so we need to special case them.
|
|
11
11
|
const binaryName = process.platform === 'win32' ? 'houdini-react.exe' : 'houdini-react'
|
|
@@ -24,10 +24,7 @@ export function useFragmentHandle<
|
|
|
24
24
|
reference: _Data | { ' $fragments': _ReferenceType } | null,
|
|
25
25
|
document: { artifact: FragmentArtifact; refetchArtifact?: QueryArtifact }
|
|
26
26
|
): any {
|
|
27
|
-
// get the fragment values
|
|
28
27
|
const fragmentData = useFragment<_Data, _ReferenceType, _Input>(reference, document)
|
|
29
|
-
|
|
30
|
-
// look at the fragment reference to get the variables
|
|
31
28
|
const { variables } = fragmentReference<_Data, _Input, _ReferenceType>(reference, document)
|
|
32
29
|
|
|
33
30
|
const client = useClient()
|
|
@@ -36,30 +33,25 @@ export function useFragmentHandle<
|
|
|
36
33
|
const [forwardPending, setForwardPending] = React.useState(false)
|
|
37
34
|
const [backwardPending, setBackwardPending] = React.useState(false)
|
|
38
35
|
|
|
39
|
-
// Stable cursor stacks for SinglePage pagination — must survive re-renders
|
|
40
36
|
const previousCursorsRef = React.useRef<(string | null)[]>([])
|
|
41
37
|
const nextCursorsRef = React.useRef<(string | null)[]>([])
|
|
42
38
|
|
|
43
39
|
const refetchArtifact = document.refetchArtifact as QueryArtifact | undefined
|
|
44
40
|
const refetchPath = refetchArtifact?.refetch?.path
|
|
45
41
|
|
|
46
|
-
// Dedicated observer for pagination queries — separate from the fragment observer.
|
|
47
|
-
// cursorHandlers derives entity variables (e.g. { id }) and artifact defaults
|
|
48
|
-
// automatically via the type config, so no manual variable extraction is needed here.
|
|
49
42
|
const paginationObserver = React.useMemo(() => {
|
|
50
43
|
if (!refetchArtifact?.refetch?.paginated) return null
|
|
51
44
|
return client.observe<_Data, _Input>({ artifact: refetchArtifact })
|
|
52
45
|
}, [refetchArtifact?.name])
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
//
|
|
47
|
+
const isSinglePage = refetchArtifact?.refetch?.mode === 'SinglePage'
|
|
48
|
+
|
|
49
|
+
// Subscribe to the pagination observer so the component re-renders when a new page lands.
|
|
50
|
+
// For SinglePage we pass disablePartial so partial cache hits (entity found but connection
|
|
51
|
+
// not yet fetched) are never resolved back to the observer — we go straight to the network
|
|
52
|
+
// and update the observer only once we have a complete page.
|
|
58
53
|
const subscribeToObserver = React.useCallback(
|
|
59
|
-
(
|
|
60
|
-
if (!paginationObserver) return () => {}
|
|
61
|
-
return paginationObserver.subscribe(onChange)
|
|
62
|
-
},
|
|
54
|
+
(fn: () => void) => paginationObserver?.subscribe(() => fn()) ?? (() => {}),
|
|
63
55
|
[paginationObserver]
|
|
64
56
|
)
|
|
65
57
|
const getObserverSnapshot = React.useCallback(
|
|
@@ -72,28 +64,13 @@ export function useFragmentHandle<
|
|
|
72
64
|
getObserverSnapshot
|
|
73
65
|
)
|
|
74
66
|
|
|
75
|
-
// Extract entity-level data from the pagination query response. For Node targetType
|
|
76
|
-
// the response is { node: EntityData }; we take the first root field to handle any type.
|
|
77
|
-
// Guard against partial cache hits (artifact has partial:true): only use the entity once the
|
|
78
|
-
// paginated connection field at refetch.path[0] is actually present in the response.
|
|
79
67
|
const paginationEntityData = React.useMemo<_Data | null>(() => {
|
|
80
68
|
if (!paginationData || !refetchArtifact?.selection?.fields) return null
|
|
81
69
|
const rootField = Object.keys(refetchArtifact.selection.fields)[0]
|
|
82
70
|
if (!rootField) return null
|
|
83
|
-
|
|
84
|
-
if (!entity) return null
|
|
85
|
-
const path = refetchArtifact.refetch?.path
|
|
86
|
-
if (path && path.length > 0 && (entity as any)[path[0]] == null) {
|
|
87
|
-
return null
|
|
88
|
-
}
|
|
89
|
-
return entity as _Data
|
|
71
|
+
return (paginationData as any)[rootField] ?? null
|
|
90
72
|
}, [paginationData, refetchArtifact])
|
|
91
73
|
|
|
92
|
-
const isSinglePage = refetchArtifact?.refetch?.mode === 'SinglePage'
|
|
93
|
-
|
|
94
|
-
// For SinglePage: use the pagination observer's entity data (each page has its own
|
|
95
|
-
// cache key) once a page fetch has landed. For Infinite: always use fragmentData,
|
|
96
|
-
// which reads accumulated pages from cache via the fragment's cache subscription.
|
|
97
74
|
const displayData =
|
|
98
75
|
isSinglePage && paginationEntityData !== null ? paginationEntityData : fragmentData
|
|
99
76
|
|
|
@@ -120,7 +97,19 @@ export function useFragmentHandle<
|
|
|
120
97
|
if (!refetchArtifact?.refetch?.paginated || !paginationObserver) return null
|
|
121
98
|
|
|
122
99
|
const fetchFn: FetchFn<_Data, _Input> = (args) => {
|
|
123
|
-
return paginationObserver.send({
|
|
100
|
+
return paginationObserver.send({
|
|
101
|
+
...args,
|
|
102
|
+
session,
|
|
103
|
+
stuff: { silenceLoading: true },
|
|
104
|
+
cacheParams: {
|
|
105
|
+
disableSubscriptions: true,
|
|
106
|
+
// Suppress partial cache hits so an in-flight forward navigation never
|
|
107
|
+
// briefly resolves with an entity that is missing its connection field.
|
|
108
|
+
// Full cache hits (partial: false) still resolve, so backward navigation
|
|
109
|
+
// continues to be served instantly from cache.
|
|
110
|
+
disablePartial: true,
|
|
111
|
+
},
|
|
112
|
+
})
|
|
124
113
|
}
|
|
125
114
|
|
|
126
115
|
const fetchUpdate = (args: any, updates: string[]) => {
|
|
@@ -139,8 +128,6 @@ export function useFragmentHandle<
|
|
|
139
128
|
const handlers = cursorHandlers<_Data, _Input>({
|
|
140
129
|
artifact: refetchArtifact,
|
|
141
130
|
getState: () => displayData as _Data | null,
|
|
142
|
-
// Use the observer's own variable state so cursor history is preserved
|
|
143
|
-
// across page navigations without manual tracking in the hook.
|
|
144
131
|
getVariables: () =>
|
|
145
132
|
(paginationObserver.state.variables ?? variables) as NonNullable<_Input>,
|
|
146
133
|
fetch: fetchFn,
|