Add Read-Only Offline Support Using the Offline Exchange from urql GraphCache

Kadi Kraman
InstructorKadi Kraman
Share this video with your friends

Social Share Links

Send Tweet

We'll install the Async Storage and the React Native-compatible offline storage for graphcache, and configure the news app to show cached data when offline. You'll be able to set how long data is cached for offline viewing.

Resources:

  • GraphCache offline: https://formidable.com/open-source/urql/docs/graphcache/offline/
  • React Native offline storage for Graphcache: https://github.com/FormidableLabs/urql/tree/main/packages/storage-rn
  • Async Storage: https://react-native-async-storage.github.io/async-storage/docs/install/

Expo:

  • Install Async Storage using the expo cli: expo install @react-native-async-storage/async-storage

Checkpoint: Show past data from cache when offline

Kadi Kraman: [0:00] Currently, when the user's device is offline, we show a full-screen message. In order for the user to be able to see the old data while offline, we need to convert this full-screen page to only encompass part of the screen.

[0:11] In our components directory, let's create a new file and call it, AppOfflineMessage.tsx. Here we'll import React from react and import View, Text, and StyleSheet from react-native. We'll export const AppOfflineMessage.

[0:25] This will be a React functional component and an arrow function. We'll return a view with a text saying, "You are offline". Underneath the component, we'll do a const styles = Stylesheet.create. We'll need a container style and a text style.

[0:41] For the container, we'll add a backgroundColor black, justifyContent center, alignItems center, and paddingVertical 20. As our container background color is going to be black, let's make the text color white.

[0:53] We'll need to assign the view style to be the styles.container, and the text style to be styles.text. Heading back to the app.tsx, we'll need to import the AppOfflineMessage from our components directory.

[1:05] Scrolling down to our render function, let's add it underneath the navigation container. Let's import SafeAreaProvider from react-native-safe-area-context.

[1:14] Let's wrap our whole app into a SafeAreaProvider. Heading back to the AppOfflineMessage, let's import useSafeAreaInsets from react-native-safe-area-context. Let's do const insets = useSafeAreaInsets.

[1:29] If we console.log the insets, this will tell us where on the screen it is safe to render content. In particular, since I'm using an iPhone 13 simulator, this will tell me that the bottom 34 and the top 47 display points on the screen are spoken for. We shouldn't render any content there.

[1:45] Let's convert this style into an array. Let's pass in paddingBottom to be insets.bottom. This will ensure that the offline message will be properly visible regardless of the device. There is now too much space here.

[1:58] Let's also add a marginTop of minus the bottom inset divided by two, which will make this play nicely with the bottom tab. In the app.tsx, rather than displaying the whole page offline message, let's instead conditionally, if isConnected is false, return the offline message. Otherwise, nothing.

[2:16] Almost everything we need for offline support is already packaged in the Graphcache exchange package. However, as we're using React Native, we can't use the default storage, package with the exchange.

[2:26] Urql has a separate library for the default React Native storage. This has two peer dependencies, Async Storage and NetInfo. We've already installed NetInfo. Let's also install Async Storage. Go into the docs page.

[2:38] We'll copy the installation command, paste it into our terminal, install the native dependencies, cd back to the root directory, and rebuild the app. Finally, we'll need to yarn add Urql/storage-rn. In our app.tsx, let's import makeAsyncStorage from our storage React Native library.

[2:55] Let's create const storage = makeAsyncStorage. We can optionally pass in a configuration object. This will include the data key, for example, my-app-data, and the metadata key, for example, my-app-metadata. These are the Async Storage keys used to store the data.

[3:11] Finally, we can choose the max age, which is how long you want to keep the data in a cache. For example, five days. Scrolling up, instead of importing cacheExchange from the Graphcache, let's import the offlineExchange.

[3:24] Let's replace the cacheExchange in our exchanges array with the offlineExchange. We'll also need to pass the storage as a configuration object to the offlineExchange. Everything else remains the same.

[3:34] When I turn off my WiFi and I close my locally running API server and reload the simulator, I will get the offline message. I can still see the home page data that I viewed earlier.

[3:43] However, when I tap on the story details, you'll notice that the author and the full story don't get loaded. This is because I hadn't looked at this story details modal after installing the offlineExchange, meaning that this data hasn't been saved in the cache.

[3:55] Let's start the API again and turn on WiFi. When I open the story details, and have the story details loaded in. If I turn off my Internet again and stop the API and reload the app, looking at the first story, I don't get the story details.

[4:07] Looking at the second story, I do, because the details of this story were saved in the cache.