morrys / react-relay-offline

TypeScript library files for Relay Modern Offline
https://morrys.github.io/react-relay-offline/docs/react-relay-offline.html
MIT License
224 stars 15 forks source link
indexeddb offline react react-native relay relay-modern typescript

id: react-relay-offline title: Getting Started

React Relay Offline

React Relay Offline is a extension of Relay for offline capabilities

Installation React Web

Install react-relay and react-relay-offline using yarn or npm:

yarn add react-relay react-relay-offline

Installation React Native

Install react-relay and react-relay-offline using yarn or npm:

yarn add @react-native-community/netinfo react-relay react-relay-offline

You then need to do some extra configurations to run netinfo package with React Native. Please check @react-native-community/netinfo official README.md to get the full step guide.

Main Additional Features

Contributing

Sponsors

Memorang

react-relay-offline examples

The offline-examples repository contains example projects on how to use react-relay-offline:

To try it out!

Environment

import { Network } from "relay-runtime";
import { RecordSource, Store, Environment } from "react-relay-offline";

const network = Network.create(fetchQuery);
const recordSource = new RecordSource();
const store = new Store(recordSource);
const environment = new Environment({ network, store });

Environment with Offline Options

import { Network } from "relay-runtime";
import { RecordSource, Store, Environment } from "react-relay-offline";

const network = Network.create(fetchQuery);

const networkOffline = Network.create(fetchQueryOffline);
const manualExecution = false;

const recordSource = new RecordSource();
const store = new Store(recordSource);
const environment = new Environment({ network, store });
environment.setOfflineOptions({
  manualExecution, //optional
  network: networkOffline, //optional
  start: async mutations => {
    //optional
    console.log("start offline", mutations);
    return mutations;
  },
  finish: async (mutations, error) => {
    //optional
    console.log("finish offline", error, mutations);
  },
  onExecute: async mutation => {
    //optional
    console.log("onExecute offline", mutation);
    return mutation;
  },
  onComplete: async options => {
    //optional
    console.log("onComplete offline", options);
    return true;
  },
  onDiscard: async options => {
    //optional
    console.log("onDiscard offline", options);
    return true;
  },
  onPublish: async offlinePayload => {
    //optional
    console.log("offlinePayload", offlinePayload);
    return offlinePayload;
  }
});

IndexedDB

localStorage is used as the default react web persistence, while AsyncStorage is used for react-native.

To use persistence via IndexedDB:

import { Network } from "relay-runtime";
import EnvironmentIDB from "react-relay-offline/lib/runtime/EnvironmentIDB";

const network = Network.create(fetchQuery);
const environment = EnvironmentIDB.create({ network });

Environment with PersistOfflineOptions

import { Network } from "relay-runtime";
import { RecordSource, Store, Environment } from "react-relay-offline";
import { CacheOptions } from "@wora/cache-persist";

const network = Network.create(fetchQuery);

const networkOffline = Network.create(fetchQueryOffline);

const persistOfflineOptions: CacheOptions = {
  prefix: "app-user1"
};
const recordSource = new RecordSource();
const store = new Store(recordSource);
const environment = new Environment({ network, store }, persistOfflineOptions);

CacheOptions

Store with custom options

import { Store } from "react-relay-offline";
import { CacheOptions } from "@wora/cache-persist";
import { StoreOptions } from "@wora/relay-store";

const persistOptionsStore: CacheOptions = { };
const persistOptionsRecords: CacheOptions = {};
const relayStoreOptions: StoreOptions = { queryCacheExpirationTime: 10 * 60 * 1000 }; // default
const recordSource = new RecordSource(persistOptionsRecords);
const store = new Store(recordSource, persistOptionsStore, relayStoreOptions);
const environment = new Environment({ network, store });

useQuery

useQuery does not take an environment as an argument. Instead, it reads the environment set in the context; this also implies that it does not set any React context. In addition to query (first argument) and variables (second argument), useQuery accepts a third argument options.

options

fetchPolicy: determine whether it should use data cached in the Relay store and whether to send a network request. The options are:

fetchKey: [Optional] A fetchKey can be passed to force a refetch of the current query and variables when the component re-renders, even if the variables didn't change, or even if the component isn't remounted (similarly to how passing a different key to a React component will cause it to remount). If the fetchKey is different from the one used in the previous render, the current query and variables will be refetched.

networkCacheConfig: [Optional] Object containing cache config options for the network layer. Note the the network layer may contain an additional query response cache which will reuse network responses for identical queries. If you want to bypass this cache completely, pass {force: true} as the value for this option. Added the TTL property to configure a specific ttl for the query.

skip: [Optional] If skip is true, the query will be skipped entirely.

onComplete: [Optional] Function that will be called whenever the fetch request has completed

import { useQuery } from "react-relay-offline";
const networkCacheConfig = {
  ttl: 1000
}
const hooksProps = useQuery(query, variables, {
  networkCacheConfig,
  fetchPolicy,
});

useLazyLoadQuery

import { useQuery } from "react-relay-offline";
const networkCacheConfig = {
  ttl: 1000
}
const hooksProps = useLazyLoadQuery(query, variables, {
  networkCacheConfig,
  fetchPolicy,
});

useRestore & loading

the useRestore hook allows you to manage the hydratation of persistent data in memory and to initialize the environment.

It must always be used before using environement in web applications without SSR & react legacy & react-native.

Otherwise, for SSR and react concurrent applications the restore is natively managed by QueryRenderer & useQueryLazyLoad & useQuery.

const isRehydrated = useRestore(environment);
   if (!isRehydrated) {
     return <Loading />;
   }

fetchQuery_DEPRECATED

import { fetchQuery_DEPRECATED } from "react-relay-offline";

Detect Network

import { useIsConnected } from "react-relay-offline";
import { useNetInfo } from "react-relay-offline";
import { NetInfo } from "react-relay-offline";

Supports Hooks from relay-hooks

Now you can use hooks (useFragment, usePagination, useRefetch) from relay-hooks

render-as-you-fetch & usePreloadedQuery

loadQuery

same as useQuery + environment

import {graphql, loadQuery} from 'react-relay-offline';
import {environment} from ''./environment';

const query = graphql`
  query AppQuery($id: ID!) {
    user(id: $id) {
      name
    }
  }
`;

const prefetch = loadQuery();
prefetch.next(
  environment,
  query,
  {id: '4'},
  {fetchPolicy: 'store-or-network'},
);
// pass prefetch to usePreloadedQuery()

loadLazyQuery

is the same as loadQuery but must be used with suspense

render-as-you-fetch in SSR

In SSR contexts, not using the useRestore hook it is necessary to manually invoke the hydrate but without using the await.

This will allow the usePreloadedQuery hook to correctly retrieve the data from the store and once the hydration is done it will be react-relay-offline

to notify any updated data in the store.

  if (!environment.isRehydrated() && ssr) {
      environment.hydrate().then(() => {}).catch((error) => {});
  }
  prefetch.next(environment, QUERY_APP, variables, {
         fetchPolicy: NETWORK_ONLY,
  });

Requirement

License

React Relay Offline is MIT licensed.