impress-2020/src/app/apolloClient.js
Matchu eab1b99052 use cache restore instead of field defs for Zone
This is just an implementation thing, but I realized we can just insert the Zone data into the initial Apollo cache, instead of doing weird field definitions

I _do_ still want the @client tags in the queries though, to tell them not to make server requests at all
2020-09-01 18:02:59 -07:00

119 lines
3.8 KiB
JavaScript

import { ApolloClient, createHttpLink, InMemoryCache } from "@apollo/client";
import { createPersistedQueryLink } from "apollo-link-persisted-queries";
import gql from "graphql-tag";
import cachedZones from "./cached-data/zones.json";
// Teach Apollo to load certain fields from the cache, to avoid extra network
// requests. This happens a lot - e.g. reusing data from item search on the
// outfit immediately!
const typePolicies = {
Query: {
fields: {
items: (_, { args, toReference }) => {
return args.ids.map((id) =>
toReference({ __typename: "Item", id }, true)
);
},
item: (_, { args, toReference }) => {
return toReference({ __typename: "Item", id: args.id }, true);
},
petAppearanceById: (_, { args, toReference }) => {
return toReference({ __typename: "PetAppearance", id: args.id }, true);
},
species: (_, { args, toReference }) => {
return toReference({ __typename: "Species", id: args.id }, true);
},
color: (_, { args, toReference }) => {
return toReference({ __typename: "Color", id: args.id }, true);
},
},
},
Item: {
fields: {
appearanceOn: (appearance, { args, readField, toReference }) => {
// If we already have this exact appearance in the cache, serve it!
if (appearance) {
return appearance;
}
// Otherwise, we're going to see if this is a standard color, in which
// case we can reuse the standard color appearance if we already have
// it! This helps for fast loading when switching between standard
// colors.
const { speciesId, colorId } = args;
// HACK: I can't find a way to do bigger-picture queries like this from
// Apollo's cache field reader API. Am I missing something? I
// don't love escape-hatching to the client like this, but...
let cachedData;
try {
cachedData = client.readQuery({
query: gql`
query CacheLookupForItemAppearanceReader(
$speciesId: ID!
$colorId: ID!
) {
species(id: $speciesId) {
standardBodyId
}
color(id: $colorId) {
isStandard
}
}
`,
variables: { speciesId, colorId },
});
} catch (e) {
// Some errors are expected while setting up the cache... not sure
// how to distinguish from Real errors. Just gonna ignore them all
// for now!
return undefined;
}
if (!cachedData) {
// This is an expected case while the page is loading.
return undefined;
}
const { species, color } = cachedData;
if (color.isStandard) {
const itemId = readField("id");
const bodyId = species.standardBodyId;
return toReference({
__typename: "ItemAppearance",
id: `item-${itemId}-body-${bodyId}`,
});
} else {
return undefined;
}
},
},
},
};
// The PersistedQueryLink in front of the HttpLink helps us send cacheable GET
// requests.
const persistedQueryLink = createPersistedQueryLink({
useGETForHashedQueries: true,
});
const httpLink = createHttpLink({ uri: "/api/graphql" });
const initialCache = {};
for (const zone of cachedZones) {
initialCache[`Zone:${zone.id}`] = { __typename: "Zone", ...zone };
}
/**
* apolloClient is the global Apollo Client instance we use for GraphQL
* queries. This is how we communicate with the server!
*/
const client = new ApolloClient({
link: persistedQueryLink.concat(httpLink),
cache: new InMemoryCache({ typePolicies }).restore(initialCache),
connectToDevTools: true,
});
export default client;