We'll learn about exchanges in urql and how urql passes a query through the dedupExchange
, cacheExchange
, and fetchExchanged
.
We'll replace the default cacheExchange
with GraphCache
which allows schema awareness. The result is that we'll be able to return partial data from the cache while more data is fetched
Install GraphCache and use the schema awareness feature to return partial data from cache.
Resources:
Checkpoint: Refactor story and use a story details fragment
Instructor: [0:00] In our app, when a user taps on a story, we show a loading page followed by the story details. If they open the same story details Moodle again, we don't need to show the loading page because we already have this data in the cache.
[0:12] You'll notice that some of the data is repeated from the story list and the story details. In particular, the title and the summary of the story are used both in the story list, as well as the story details.
[0:26] In theory, we should be able to display this partial data in the story details Moodle while the author and the full text are still being fetched. Let's open our story details Moodle, and let's console.log the data.
[0:40] If I refresh the app and open the story details Moodle, we'll see that we get two logs. The first one has data undefined, and the second one has all the data. Currently, even though we partially have requested this data, it's not being returned from the cache.
[0:55] Graphcache is a normalized caching solution for Urql. There is extensive documentation for graphcache in the Urql documentation site. To make the long story short, graphcache is the main tool that's going to enable our news app to become offline capable.
[1:13] Let's head over to graphcache and scroll down to installation and setup. From here, let's copy the installation command and install the library. Let's open App.tsx and take a look at our create client. This here is the minimal configuration for the Urql client.
[1:28] It has a default value for exchanges, which is an array that consists of the dedupExchange, the cacheExchange, and the fetchExchange. These can all be imported from Urql.
[1:39] So far, we haven't had to pass these in when we create our client, because these are already the default exchanges. The way Urql works is, when we do useQuery from a component, this request goes into the dedupExchange, which filters out any duplicate queries. Then it goes into the cacheExchange. The default cacheExchange for Urql is using document caching, which is simple, but powerful.
[2:01] Depending on your fetch policy, if your query is already in the cache, it doesn't get passed on to the next exchange, but gets returned straight away, which is why we don't see a network request when we open a story details Moodle of the same story twice.
[2:13] If the data is not in the cache, or if our request policy states that we should do a request anyway, it gets passed over to the fetchExchange which actually handles doing the API request.
[2:23] The response then gets passed back into the cacheExchange, where it gets stored to the cache and through the dedupExchange, and it gets returned from our useQuery hook. Let's import cacheExchange from graphcache. Let's delete the cacheExchange import from Urql. Finally, we'll need to initialize graphcache and pass in a config object.
[2:43] Let's import our schema, and let's pass it into our cacheExchange. Doing this will enable schema awareness. You can read more about it in the schema awareness section. One of the features this enables is being able to generate partial results.
[2:57] Let's add a resolver section and let's do a query and story. When the user queries for a particular story -- let's pass in args -- we want to return an object which will tell where in the cache to look for the story. All the GraphQL entities can be uniquely identified using two fields -- the type name, in our case, story and ID, which will be args.ID, which is what we passed into the story query.
[3:24] When we reload our app and open a story details page, we'll see the partial data already prepopulated while the additional information is being fetched.