Skip to content

Commit

Permalink
Show partial data from list view in details
Browse files Browse the repository at this point in the history
Since we already have most of the information that we want to show for
the character in the cache from the list query, then we can improve the
user experience by showing most of that data to the user while the rest
are still loading.

There are two main pieces of the puzzle for this:

1. [`returnPartialData` option for
   `useQuery`](https://www.apollographql.com/docs/react/data/queries/#returnpartialdata),
   which lets Apollo Client return a partial response from the cache, if
   we have *anything* there already.
2. The `read` function for `character` query `typePolicies` allows us to
   return an existing object from the cache if we already have something
   saved there (e.g., a Character with the correct ID, but under a
   different query).
  • Loading branch information
JoosepAlviste committed Nov 15, 2022
1 parent 09ad51b commit a3b3aac
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 15 deletions.
37 changes: 24 additions & 13 deletions src/components/DetailView.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
<template>
<div v-if="loading">Loading...</div>
<div v-if="!character && loading">Loading...</div>

<div v-else-if="character" class="details">
<h2>
{{ character.name }} (<router-link to="/">Back to list</router-link>)
</h2>
<img v-if="character.image" :src="character.image" class="image" />
<div>Gender: {{ character.gender }}</div>
<div>Status: {{ character.status }}</div>
<div>Species: {{ character.species }}</div>
<div>
<div>Episodes:</div>
<ul class="episodes-list">
<li v-for="episode in character.episode">
{{ episode?.name }}
</li>
</ul>
</div>
<template v-if="character.episode">
<div>Gender: {{ character.gender }}</div>
<div>Status: {{ character.status }}</div>
<div>Species: {{ character.species }}</div>
<div>
<div>Episodes:</div>
<ul class="episodes-list">
<li v-for="episode in character.episode">
{{ episode?.name }}
</li>
</ul>
</div>
</template>
<div v-else-if="loading">Loading...</div>
</div>
</template>

Expand Down Expand Up @@ -46,7 +49,15 @@ const { result, loading } = useQuery(
}
}
`),
{ characterId: props.id }
{ characterId: props.id },
{
// This allows Apollo Client to return us data in `result` even if not all
// the required fields exist.
//
// Read more about this option in the Apollo Client docs:
// https://www.apollographql.com/docs/react/data/queries/#returnpartialdata
returnPartialData: true,
}
);

const character = computed(() => result.value?.character);
Expand Down
36 changes: 34 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createApp, provide, h } from 'vue';
import { createRouter, createWebHashHistory } from 'vue-router';
import { DefaultApolloClient } from '@vue/apollo-composable';
import { ApolloClient } from '@apollo/client/core';
import { ApolloClient, gql } from '@apollo/client/core';
import { InMemoryCache } from '@apollo/client/cache';

import App from './App.vue';
Expand All @@ -20,7 +20,39 @@ const router = createRouter({

const apolloClient = new ApolloClient({
uri: 'https://rickandmortyapi.com/graphql',
cache: new InMemoryCache(),
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
character: {
read(existing, { args, toReference, cache }) {
if (!args || existing) {
return existing;
}

const ref = toReference({
__typename: 'Character',
id: args.id,
});

// Check if we have an existing quote already saved into Apollo
// Cache.
const existingCharacter = cache.readFragment({
id: ref?.__ref,
fragment: gql`
fragment MyCharacter on Character {
id
}
`,
});

return existingCharacter ? ref : undefined;
},
},
},
},
},
}),
});

const app = createApp({
Expand Down

0 comments on commit a3b3aac

Please sign in to comment.