Skip to content

Commit 82ee741

Browse files
committed
feat(playground): add useFragment example with reactive state and UI enhancements
1 parent 0167443 commit 82ee741

File tree

2 files changed

+111
-1
lines changed

2 files changed

+111
-1
lines changed

packages/nuxt/playground/pages/index.vue

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import type { PostsQueryVariables } from '@vue3-apollo/operations'
33
44
import { gql } from '@apollo/client'
5-
import { PostsDocument, UpdatePostDocument } from '@vue3-apollo/operations'
5+
import { PostDetailFragmentDoc, PostsDocument, UpdatePostDocument } from '@vue3-apollo/operations'
66
import { reactive, ref } from 'vue'
77
88
// Constants
@@ -20,6 +20,8 @@ const rawQuery = gql`
2020
// Refs
2121
const enabled = ref(true)
2222
const title = ref('')
23+
const fragmentPostId = ref(1)
24+
const fragmentEnabled = ref(true)
2325
2426
// Reactive variables
2527
const vars = reactive<PostsQueryVariables>({
@@ -49,6 +51,23 @@ const { error: rawQueryError, result: rawQueryResult } = useQuery(rawQuery, rawQ
4951
keepPreviousResult: true
5052
})
5153
54+
// Fragments
55+
const {
56+
complete: fragmentComplete,
57+
data: fragmentData,
58+
error: fragmentError,
59+
missing: fragmentMissing,
60+
onResult: onFragmentResult,
61+
result: fragmentResult
62+
} = useFragment({
63+
enabled: fragmentEnabled,
64+
fragment: PostDetailFragmentDoc,
65+
from: computed(() => ({
66+
__typename: 'Post',
67+
id: fragmentPostId.value
68+
}))
69+
})
70+
5271
// Mutations
5372
const { loading, mutate } = useMutation(UpdatePostDocument)
5473
@@ -57,6 +76,22 @@ onResult((data) => {
5776
console.warn('onResult', data)
5877
})
5978
79+
onFragmentResult((result) => {
80+
console.warn('onFragmentResult', result)
81+
})
82+
83+
// Watch fragment result for type narrowing demo
84+
watchEffect(() => {
85+
if (fragmentResult.value?.complete) {
86+
// TypeScript knows data is non-optional here
87+
console.warn('Fragment complete:', fragmentResult.value.data)
88+
}
89+
else if (fragmentResult.value?.data) {
90+
// Partial data
91+
console.warn('Fragment partial:', fragmentResult.value.data)
92+
}
93+
})
94+
6095
// Composables
6196
const route = useRoute()
6297
const isLoading = useQueriesLoading()
@@ -185,6 +220,80 @@ watch(isLoading, (loading) => {
185220
{{ (rawQueryResult as any)?.users }}
186221
</pre>
187222
</div>
223+
224+
<!-- Fragment Testing Section -->
225+
<div class="border-t border-white/10 pt-4 space-y-3">
226+
<div class="flex items-center gap-3 mb-3">
227+
<h3 class="text-sm font-medium text-gray-300">
228+
Fragment Testing (useFragment)
229+
</h3>
230+
<button
231+
type="button"
232+
class="inline-flex cursor-pointer items-center gap-2 px-2 py-1 rounded text-xs bg-slate-800 hover:bg-slate-700 active:bg-slate-800 text-gray-200 border border-white/10 transition-colors"
233+
@click="fragmentEnabled = !fragmentEnabled"
234+
>
235+
{{ fragmentEnabled ? 'Disable' : 'Enable' }}
236+
</button>
237+
<div class="flex items-center gap-2">
238+
<label class="text-xs text-gray-400">Post ID:</label>
239+
<input
240+
v-model.number="fragmentPostId"
241+
type="number"
242+
min="1"
243+
class="w-20 px-2 py-1 text-xs rounded bg-slate-800/70 text-gray-100 border border-slate-700 focus:(outline-none ring-1 ring-indigo-500)"
244+
>
245+
</div>
246+
<div class="ml-auto flex items-center gap-2">
247+
<span class="text-xs text-gray-400">Complete:</span>
248+
<span :class="fragmentComplete ? 'text-emerald-400' : 'text-amber-400'" class="text-xs font-medium">
249+
{{ fragmentComplete ? '✓ Yes' : '⚠ Partial' }}
250+
</span>
251+
</div>
252+
</div>
253+
254+
<div v-if="fragmentError" class="text-sm text-rose-400 bg-rose-900/20 border border-rose-700/40 rounded-lg p-3">
255+
{{ fragmentError }}
256+
</div>
257+
258+
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
259+
<div>
260+
<div class="text-xs text-gray-400 mb-2">
261+
Fragment Data (from cache):
262+
</div>
263+
<pre class="w-full overflow-auto text-sm leading-relaxed bg-slate-950/60 border border-white/10 rounded-lg p-3">
264+
{{ fragmentData }}
265+
</pre>
266+
</div>
267+
268+
<div>
269+
<div class="text-xs text-gray-400 mb-2">
270+
Full Result (type-safe):
271+
</div>
272+
<pre class="w-full overflow-auto text-sm leading-relaxed bg-slate-950/60 border border-white/10 rounded-lg p-3">
273+
{{ fragmentResult }}
274+
</pre>
275+
</div>
276+
</div>
277+
278+
<div v-if="fragmentMissing" class="text-xs">
279+
<div class="text-amber-400 mb-2">
280+
Missing Fields:
281+
</div>
282+
<pre class="w-full overflow-auto text-xs leading-relaxed bg-amber-950/20 border border-amber-700/40 rounded-lg p-3">
283+
{{ fragmentMissing }}
284+
</pre>
285+
</div>
286+
287+
<div class="text-xs text-gray-500 bg-slate-800/30 border border-white/5 rounded-lg p-3">
288+
<strong>💡 Tips:</strong>
289+
<ul class="mt-2 space-y-1 list-disc list-inside">
290+
<li>Fragment reads data synchronously from Apollo Cache</li>
291+
<li>Update post title above to see fragment auto-update</li>
292+
<li>Change Post ID to read different entities</li>
293+
<li>Use <code class="px-1 py-0.5 bg-slate-700 rounded">result.value?.complete</code> for TypeScript type narrowing</li>
294+
</ul>
295+
</div>
296+
</div>
188297
</section>
189298

190299
<footer class="mt-8 text-center text-xs text-gray-500">

packages/nuxt/src/module.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default defineNuxtModule<ApolloModuleOptions>({
3737
imports: [
3838
// composables
3939
'useApolloClient',
40+
'useFragment',
4041
'useMutation',
4142
'useQuery',
4243
'useSubscription',

0 commit comments

Comments
 (0)