Code Monkey home page Code Monkey logo

react-relay-offline's Introduction

Hi there πŸ‘‹

I am an independent OSS developer and in my spare time I work in the creation of libraries that allow the management of offline applications in web and react-native contexts. I actively follow the GraphQL world with particular attention to Relay.

The main libraries I created are:

πŸ”­ I’m currently working on:

  • relay-hooks v4.0.0
  • react-relay-offline v3.0.0
  • relay-angular v1.0.0

πŸ“« My social accounts:

react-relay-offline's People

Contributors

akinncar avatar dependabot[bot] avatar helielson avatar ieschalier avatar morrys avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-relay-offline's Issues

Array Warning: The record contains two instances of the same id

Hi,

I'm querying some fields and get the following warning:

Warning: RelayResponseNormalizer: Invalid record. 
The record contains two instances of the same id: 
`RW50bmFobWVwcm90b2tvbGxQYXJhbWV0ZXI6Njc=` with conflicting field, optionen and its values: nein,ja and nein,ja. If two fields are different but share the same id, one field will overwrite the other.

So far I am seeing this warning only for fields defined in Graphql as array of strings ([String]), and independent of the content.
An empty array [] throws the same error as an array of ["nein", "ja"]

The warning does not occur in 'store-only' mode.

Retrying mutations on network failure

Hi Morries,

im currently testing the replay of mutations in case of network failure.

Pure offline/online mode works fine, however as soon as a network query fails that one is not replayed again.
The local store reflects the change, but it won't be communicated to the server.

Am I doing something wrong here, or is this intentional? I'm kinda looking for a retry strategy, the assumption is that users may have a flaky internet connection and requests my fail due to that but should be replayed later on.

error executing mutations offline without the network parameter

Hello!
I use Create-react-app for the application and thus I use import graphql from "babel-plugin-relay/macro"; because I don't have a customizable .babelrc. The library seems to work one way. It stores everything into the localStorage but when the connection is back it just doesn't do anything

Deprecate relay-hooks in favour of the built-in hooks

Since it was vaguely discussed in #109 , I thought I'd create an issue to guage interest and track progress toward switching over to the built-in hooks.

With relay well into v14 v15 and pushing for suspense and error boundaries, I expect people will want to use this new feature rather quickly. There are already three people who expressed desire for this feature in other issues.

I might be able to find time to help with this process if you're interested.

  • Update offline hooks to use built-ins (includes API changes)
  • Update suspense exemple (still on relay v9)

[RFC] create a FAQ section

How the react-relay-offline version is managed

  • Patch release ..1 : backward compatible & bug fixes
  • Minor release *.1.0 : backward compatible or small breaking change & new small improvements
  • Major release 1.0.0 : breaking change | new important improvements

I recommend using ~ and not ^ in the react-relay-offline version and follow this repository for any update

What are the main dependencies of react-relay-offline?

react-relay-offline uses these libraries to manage the offline:

  • wora/cache-persist
    • manages the status and its persistence in the storage
  • wora/netinfo
    • manages the network status detection
  • wora/offline-first
    • manages all the offline workflow with queuing requests
  • wora/relay-store
    • extension of the Store and Recordsource objects with the integration of wora/cache-persist + TTL
  • wora/relay-offline
    • extension of the relay environment with the integration of the wora/offline-first library

I recommend following the repository wora for any details.

How should I manage the creation of a new node?

When a new node is created by mutation the id must be generated in the browser to use it in the optimistic response.
This ensures the consistency of the store.

offline needs optimistic updater?

the offline needs to have one of the following options:

  • only optimisticResponse
  • optimisticResponse + updater
  • configs
  • optimisticUpdate

Multiple calls of useMutation into offline mode

Hi, I have a doubt about what happens when I have multiple mutations happening into offline mode and the internet goes back online. Today I try to use the useMutation with this configuration and only the last mutation made into offline mode is synced with the server when internet goes back online. I need extra configurations to have multiple mutations into the queue to be performed when internet goes back online?

const [updateStoreCategory] = useMutation<StoreCategoryListUpdater_Mutation>(
  graphql`
    mutation StoreCategoryListUpdater_Mutation(
      $addConnections: [ID!]!
      $deleteConnections: [ID!]!
      $input: UpdateStoreCategoryInput!
    ) @raw_response_type {
      updateStoreCategory(input: $input) {
        store
          @appendNode(
            connections: $addConnections
            edgeTypeName: "StoreEdge"
          ) {
          id @deleteEdge(connections: $deleteConnections)
          category
        }
      }
    }
  `
)

const update = () => {
  updateStoreCategory({
    variables: {
      input: {
        storeId: store.id,
        category: newCategory,
      },
      deleteConnections,
      addConnections: [
        getSafeConnectionID('root', 'StoreList_stores', {
          where: { category: { eq: newCategory } },
        }),
      ],
    },
    optimisticResponse: {
      updateStoreCategory: {
        store: {
          id: store.id,
          category: newCategory,
        },
      },
    },
  })
}

fetchQuery results not being added to store cache

It's quite possible this is because of another library I'm using (or I've set something up wrong), but would at least like to check my usage appears OK...

I'm finding caching and Async storage persistance is generally working great πŸ‘
If I print out environment._store._cache.data I can see the queries I have visited successfully being added. The one exception to this is a query that I call imperatively using fetchQuery, which is causing me problems.

I create my Network/Environment like this:

import {
    RelayNetworkLayer,
    urlMiddleware,
    authMiddleware,
    errorMiddleware,
    loggerMiddleware,
    retryMiddleware,
    batchMiddleware
} from 'react-relay-network-modern'

const config = { noThrow: true }

const network = new RelayNetworkLayer(
    [
        urlMiddleware({
            url: () => Promise.resolve(`${API_BASE_URI}/graphql/`)
        }),
        batchMiddleware({
            batchUrl: () => Promise.resolve(`${API_BASE_URI}/graphql/`),
            batchTimeout: 80
        }),
        authMiddleware({
            token: AsyncStorageController.getAuthToken,
            prefix: 'Token '
        }),
        retryMiddleware({
            fetchTimeout: 10 * 1000, // 10 seconds
            retryDelays: attempt => Math.pow(2, attempt + 4) * 100
        }),
        loggerMiddleware(),
        errorMiddleware()
    ],
    config
)

const persistStoreOptions = { defaultTTL: 1000 * 60 * 60 }

const recordSource = new RecordSource(persistOptions)

const store = new Store(recordSource, persistStoreOptions)

const env = new Environment(
            {
                network,
                store
            },
            {}
        )

I am then using fetchQuery like this:

import { fetchQuery, graphql } from 'react-relay-offline'
export const query = graphql`
    query appStartQuery {
        viewer {
            me {
                id
            }
       }
    }
`
const data = await fetchQuery(relayEnv.environment, query)

Is there any setup here for react-relay-offline I've missed? Is there anything I could debug here that might point me in the right direction?

Potential issue with offline mutation queue / is online logic

Hi!

I've been testing the offline logic around firing mutations in our app, and it seems like the offline mutation queue isn't firing until we hard close our react-native app - then it fires.

When I come online, the queryRenderer completes queries correctly, but otherwise doesn't seem to fire the expected mutations, until later when we hard close the app.

There may be an issue here with the isOnline detection in the library - or maybe I'm not doing something right!

I hope that is helpful.

versions:

"react-relay": "~7.1.0",
"react-relay-network-modern": "~4.4.0",
"react-relay-offline": "~1.1.0",

Support of Expo

Hi,
I tried to use your library as an expo react-native project and I have no luck to make it work.

You can check this minimal failing repo - https://github.com/Emetrop/relay-offline-test

This is dump from console

Error: Unable to resolve module `./debugger-ui/debuggerWorker.d9da4ed7` from ``: 

None of these files exist:
  * debugger-ui/debuggerWorker.d9da4ed7(.native|.native.expo.ts|.expo.ts|.native.expo.tsx|.expo.tsx|.native.expo.js|.expo.js|.native.expo.jsx|.expo.jsx|.native.ts|.ts|.native.tsx|.tsx|.native.js|.js|.native.jsx|.jsx|.native.json|.json|.native.wasm|.wasm)
  * debugger-ui/debuggerWorker.d9da4ed7/index(.native|.native.expo.ts|.expo.ts|.native.expo.tsx|.expo.tsx|.native.expo.js|.expo.js|.native.expo.jsx|.expo.jsx|.native.ts|.ts|.native.tsx|.tsx|.native.js|.js|.native.jsx|.jsx|.native.json|.json|.native.wasm|.wasm)
    at ModuleResolver.resolveDependency (/Users/martin/Work/personal/relay-offline-test/node_modules/metro/src/node-haste/DependencyGraph/ModuleResolution.js:163:15)
    at ResolutionRequest.resolveDependency (/Users/martin/Work/personal/relay-offline-test/node_modules/metro/src/node-haste/DependencyGraph/ResolutionRequest.js:52:18)
    at DependencyGraph.resolveDependency (/Users/martin/Work/personal/relay-offline-test/node_modules/metro/src/node-haste/DependencyGraph.js:282:16)
    at /Users/martin/Work/personal/relay-offline-test/node_modules/metro/src/lib/transformHelpers.js:267:42
    at /Users/martin/Work/personal/relay-offline-test/node_modules/metro/src/Server.js:1305:37
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (/Users/martin/Work/personal/relay-offline-test/node_modules/metro/src/Server.js:99:24)
    at _next (/Users/martin/Work/personal/relay-offline-test/node_modules/metro/src/Server.js:119:9)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)

and screenshot from app
image

so probably it's an issue with not supported AsyncStorage by expo which is explained here right?

react-native-async-storage/async-storage#72

So it means you can't do anything with that and we need to wait for adding support for AsyncStorage by expo?

Cached QueryRender refreshing

Hi,

I'm just testing the library (it sounds perfect), but have some strange behavior I do not understand:

When I'm using any offline mode, the QueryRenderer does not update the view correctly. Using a network request works just fine.

Basically only 'Loading' is shown, as if the props never populate (but the log shows differently)

Here is the sample I am using:

import React from 'react';
import './App.css';
import _ from 'lodash';

import ReactEnvironment from './ReactEnvironment';
import {NETWORK_ONLY, STORE_ONLY, STORE_OR_NETWORK, STORE_THEN_NETWORK} from 'react-relay-offline';


import graphql from 'babel-plugin-relay/macro';
import {QueryRenderer} from 'react-relay-offline';


function App() {
  return (
    <div className="App">
      <header className="App-header">
      <QueryRenderer
          environment={ReactEnvironment}
          fetchPolicy={'store-or-network'}
          variables={{}}
          query={graphql`
            query AppQuery {
              auftraggeber {
                edges {
                  node {
                    id
                    name
                  }
                }
              }
            }
          `}
          render={({props, error, retry, cached}) => {
            console.log('props')
            console.log(props)
            console.log('cached')
            console.log(cached)
            if (props) {
              let rows = [];
              _.each(props.auftraggeber.edges, (ele) => {
                rows.push(<p key={ele.node.id}>{ele.node.name} </p>);
              })
              console.log('returning rows..')
              console.log(rows)
              return <div>{rows}</div>;
            } else {
              return <div>Loading</div>;
            }

            // return (
            //   <button onClick={retry} className="refetch">
            //     Retry
            //   </button>
            // );
          }}
        />

      </header>
    </div>
  );
}

export default App;


The logging comes out a bit weird as well (pure offline log here) showing cached false in the end:
props

App.js:37 null
App.js:40 cached
App.js:41 false
App.js:36 props
App.js:37 null
App.js:40 cached
App.js:41 false
ReactEnvironment.js:45 start offline []
ReactEnvironment.js:50 finish offline undefined []
App.js:36 props
App.js:37 {auftraggeber: {…}}auftraggeber: edges: (2)Β [{…}, {…}]0: {node: {…}}1: {node: {…}}length: 2__proto__: Array(0)proto: Object__proto__: Object
App.js:40 cached
App.js:41 true
App.js:48 returning rows..
App.js:49 (2)Β [{…}, {…}]
App.js:36 props
App.js:37 {auftraggeber: {…}}auftraggeber: edges: (2)Β [{…}, {…}]proto: Object__proto__: Object
App.js:40 cached
App.js:41 false
App.js:48 returning rows..
App.js:49 (2)Β [{…}, {…}]

Offline equivalent of createMockEnvironment

Hi morrys!

I'm trying to unit test using this kind of approach on Relay v11.0.2, relay-offline v4.0.0

I am fetching like this:

    const isRehydrated = useRestore(environment)

    const qrOptions = {
        fetchPolicy,
        ttl,
        networkCacheConfig: options.cacheConfig
    }

    const { data, error: _error, retry, isLoading: relayLoading } = useQuery(
        options.query,
        variables,
        qrOptions
    )

    if (!isRehydrated || !data) {
        return <Loading />
    }

    return <Component {...data}/>

Typically I would pass in environment={createMockEnvironment()} here, but if I do that it fails because I'm missing offline-specific functions: TypeError: environment.isRehydrated is not a function

If I then try and mock these in a simple way (e.g. returning true for isRehydrated and isOffline) the data returns null.

I saw you had a mock in the codebase here, but this seems to have a lot of complexity I'd rather not replicate.

Is there anything simple I can add as a wrapper around createMockEnvironment that would allow me to fetch data in my tests?

new release - supports relay v9.0.0

This issue is in progress in the following branches:
react-relay-offline: https://github.com/morrys/react-relay-offline/tree/relay-v9

wora: https://github.com/morrys/wora/tree/relay-v9 (issue morrys/wora#31)

  • optimize store request identifier facebook/relay#2985
    • at the moment I have solved the problem in @ wora/relay-store
  • added tests in wora/relay-store morrys/wora#39
  • added tests in wora/relay-offline
  • added tests in wora/offline-first
  • added tests in wora/netinfo
  • support relay v8.0.0 & v9.0.0
  • upgrade relay-hooks
  • check the compatibility between the query TTL and the new Relay store data invalidation feature
  • added tests in react-relay-offline
  • eslint & prettier
  • CI action
  • release wora/relay-offline & wora/relay-store
  • upgrade wora/relay-offline & wora/relay-store

App crashes after updating from Relay 7 to Relay 11 with undefined operation

After upgrading from Relay 7 to Relay 11, we've been having a crash in our app that's quite hard to reproduce.

It seems to happen when we open from the background using a useQuery hook with fetch policy 'store-then-network', so it must be booting from the offline store. Previously we were using a QueryRenderer.

We upgraded from those versions:

    "react-relay": "~7.1.0",
    "react-relay-network-modern": "~4.7.7",
    "react-relay-offline": "~1.1.0",
    "relay-compiler": "~7.1.0",
    "relay-compiler-language-typescript": "~10.1.3",

to the following versions

    "react-relay": "11.0.2",
    "react-relay-network-modern": "~4.7.7",
    "react-relay-offline": "4.0.0",
    "relay-compiler": "11.0.2",
    "relay-compiler-language-typescript": "~14.1.1",
    "@types/relay-runtime": "12.0.0"

Remote Sentry stack trace

Screenshot 2021-11-28 at 13 01 09

Local stack trace

Image from iOS (1)

useRestore not working anymore after update to v3

Hi, I updated to v3 and running into an issue where I'm stuck in loading state at the boot of my app (react-native).
I'm using the useRestore hook to know if the store is rehydrated as per the docs.
const isRehydrated = useRestore(environment)
I'm now stuck because isRehydrated is always false and I don't see any errors.
I tried to console log the environment after the useRestore call :
Screenshot 2021-01-27 at 17 21 51
There seems to be something going on in promisesRestore, not sure if it's related?
Any idea of what's going on? What can I try?

Is PersistGate required.

Does this solution still require the need for PersistGate to make sure the hydrate is finished before the QueryRenderers's are mounted?

isLoading seemingly incorrectly returning true for a single render

I have a slightly confusing situation that's causing a problem in a test, but possibly might happen outside of tests also.

My code looks like this (using v5.0.0 of react-relay-offline):

        const {
            data,
            error: _error,
            retry,
            isLoading: relayLoading,
        } = useQuery(options.query, variables, options)

        const isConnected = useIsConnected()
        const isOffline = !isConnected

        if (!isRehydrated) {
            return null
        }

        let networkError = false
        let error = _error
        if (!data && isOffline) {
            // We're offline and have an empty cache: show the network error screen.
            error = new NetworkError()
            networkError = true
        }

        const mostRecent = relayEnv.environment.mock.getAllOperations()[0] //debugging

        console.log(
            `data returned: ${!!data}, `,
            `relayLoading: ${relayLoading}, `,
            `isConnected: ${isConnected}, `,
            `relayOperations: ${relayEnv.environment.mock
                .getAllOperations()
                .map((operation) => operation && operation.request.node.fragment.name)}, `,
            `environment.mock.isLoading: ${
                mostRecent && relayEnv.environment.mock.isLoading(mostRecent)
            }`
        )

        return (
            <Component />

I run one test fine, switching from one test to the other I run:

beforeEach(() => {
        environment.clearCache()
        jest.clearAllMocks()
        jest.useFakeTimers()
    })

    afterEach(async () => {
        jest.runOnlyPendingTimers()
        jest.useRealTimers()
    })

then the second test I get this sequence of logs:

data returned: false,  relayLoading: true,  isConnected: undefined,  relayOperations: HomeScreenQuery,  environment.mock.isLoading: false

data returned: false,  relayLoading: true,  isConnected: true,  relayOperations: HomeScreenQuery,  environment.mock.isLoading: false

data returned: false,  relayLoading: false,  isConnected: true,  relayOperations: HomeScreenQuery,  environment.mock.isLoading: false // <<< This is the problematic render

data returned: false,  relayLoading: true,  isConnected: undefined,  relayOperations: HomeScreenQuery,  environment.mock.isLoading: false

data returned: false,  relayLoading: true,  isConnected: true,  relayOperations: HomeScreenQuery,  environment.mock.isLoading: false

// At this point I run "environment.mock.resolveMostRecentOperation"

data returned: true,  relayLoading: false,  isConnected: true,  relayOperations: ,  environment.mock.isLoading: undefined // <<< At this point we're OK

If I switch the tests round I get the same thing on the second test. So I think there must be some state persisting between the stores (or a mock not being rest somehow)

I appreciate I haven't shown you any of the code around this (I didn't want to overwhelm with information just yet), but are you aware of a situation that could occur where isLoading changes from true -> false even though no data is returned yet, before then loading a couple of cycles later? It looks to me like there's an operation logged in Relay the entire time as well.

Is there anything I could log from the store (or elsewhere) that might help debug this?

I have seen the odd random error screen flash in our app, which makes me wonder if this also happens outside of tests.

TypeError: undefined is not an object (evaluating 'selector.node.name')

Hey, I just tried setting up this project using react native and whenever I make the switch to relay-react-offline my entire app stops working and I get an error screen of death like so:

Screenshot 2020-02-19 at 17 57 00

My code looks something like this:

import {Network} from 'relay-runtime'
import {RecordSource, Store, Environment} from 'react-relay-offline'
import {RelayPaginationProp} from 'react-relay'
import {useCallback} from 'react'

async function fetchQuery(operation: any, variables: Record<string, any>) {
  const response = await fetch('http://localhost:3000/graphql', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      query: operation.text,
      variables,
    }),
  })
  return response.json()
}

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

And my package.json file is like this (I removed the irrelevant parts)

{
  "dependencies": {
    "@react-native-community/async-storage": "^1.8.0",
    "@react-native-community/netinfo": "^5.5.0",
    "react": "16.9.0",
    "react-native": "0.61.5",
    "react-relay": "^9.0.0",
    "react-relay-network-modern": "^4.5.0",
    "react-relay-offline": "^1.1.0",
    "relay-runtime": "^8.0.0",
  }
}

The error seems to arrive from the Store.js file and I get a typescript error also due to a type mismatch with the store property:

Screenshot 2020-02-19 at 17 59 12

The transcript is:

Types of property 'retain' are incompatible.
    Type '(selector: NormalizationSelector, retainConfig?: { ttl?: number | undefined; } | undefined) => Disposable' is not assignable to type '(operation: OperationDescriptor) => Disposable'.
      Types of parameters 'selector' and 'operation' are incompatible.
        Type 'OperationDescriptor' is missing the following properties from type 'NormalizationSelector': dataID, node, variablests(2322)
RelayModernEnvironment.d.ts(32, 14): The expected type comes from property 'store' which is declared here on type 'EnvironmentConfig'

Refetch containers

Noticed on your README.md you said:

TODO:
Implementation of Refetch Container Offline

Just wondering if you could expand a little more on what you think the library is missing to support Refetch Containers.

I have used createRefetchContainer in my native offline example app and seems to work ok from a first pass.

See container here: https://github.com/robertpitt/react-relay-offline-native-example/blob/feature/fragment-container-v0.2.0/src/pages/Cinimas/index.ts, ui code in Cinimas.tsx.

Prevent persisting of errors from queries

There might already be some smart solution to this in the library, but I've not been able to find anything on it yet.

We use React Native and persist state to Async Storage. Unfortunately, we're still on an older version of react-relay-offline (1.1.0) so not sure if this question has been resolved later on.

The problem flow is:

  • Let's say we have an error on the server
  • App users open the app. The result of this is persisted to AsyncStorage.
  • We fix the error on the server
  • These users' apps continue to crash because their apps load up the "broken" cache result from async storage

To me it would make sense to either:

  1. Not store query results if there was an error
  2. Clear the Async Storage if there was an app crash

Are there any nice solutions to this built into the library? Or is this something we should implement?

NETWORK_THEN_CACHE policy.

This issue is to discuss how to handle cases where we would like to try to make a network request first before using the store/cache.

This is desirable where we prefer up-to-date information, but will settle for out of data information. It seems like a common use case for offline apps, making it worth at least discussing in the context of this library.

An example might be trying to fetch comments. We don't want to show the old comments if the new ones are available, but rather want to try to fetch the latest comments first, but are happy to default to showing the old ones if necessary.

React Native Support

Hey Lorenzo,

Amazing work so far, I have been thinking about an offline mode in our react native application for a little while now and during the design that your library takes is very similar to what we came up with.

We have been doing some interesting stuff using this approach, such as seeding data into the store via fetchQuery and doing some post store updates to simulate root queries, allowing us to perform initial sync and then be able to function completely offline by optimistically adding root nodes to allow offline mode for seeded data rather than just a rolling cache.

I haven't run this project as of yet but I have read over the code, I am just wondering about your choice for using idb and it's a potential incompatibility with react-native.

v0.11.0

  • upgrade of the library that manages the persistence of the stores morrys/wora#11
  • retry should check if environment is online. #20
  • Improve the handling of Loading in react-native #21

_this._store.setCheckGC is not a function

I have this error in trying to follow the example of README with React Native.

ERROR  TypeError: _this._store.setCheckGC is not a function. (In '_this._store.setCheckGC(function () {
       return _this.isOnline();
     })', '_this._store.setCheckGC' is undefined)

My Environment:

"react-native": "0.64.2",
"react-relay-offline": "^4.0.0",
"relay-hooks": "^5.0.0",
"@react-native-community/netinfo": "^6.0.2",

Allow offline execution of mutations that do not modify the store

I've just upgraded from 0.11.1 -> 1.0.2 (and upgraded Relay to v6 - I've also tried v7).

When I turn my connection off to test offline, on one screen I get this error TypeError: Cannot read property 'toJSON' of undefined from the OfflineFirstRelay file in relay-offline.

It comes from this line:

var sinkPublish = environment
                    .getStore()
                    .getSource()
                    ._sink.toJSON();

This only seems to happen on one screen, I have done some digging and can't see specifically why this would error and other screens not. I can dive into this further, but just wanted to see if there was anything obvious I've missed in the upgrade.

My relay-offline library in my yarn.lock is at the right version "@wora/relay-offline@^2.0.4"

I have also followed your react-native example (e.g. I've added useRestore above my QueryRenderer).

Store doesn't persist data after rebuilding it when logging out

When logging out, we rebuild a new environment like this:

    const store = new Store(recordSource, persistOptionsStore, relayStoreOptions)
    const env = new Environment(
        {
            network,
            store,
        },
        {}
    )

but the issue is that mutations aren’t updating the store until we hard restart the app.

Is there anythign specific we need to do when logging out?

Offline Sync Query (DeltaSync)

Hey,

Just looking at the redux persist/hydrate store, and feel as though the naming is a little off here, take a look at the following screenshot.

Screen Shot 2019-05-19 at 22 42 03

I would expect that AppQuery.{....} should contain the root operation, such as AppQuery. allCinemaDetails{ ... }.

react-relay-offline useRestore & state reconciliation

the useRestore hook allows you to manage the restore of data persisted in the storage.
To be used if relay components are used outside of the QueryRenderer or for web applications without SSR & react-native (

const isRehydrated = useRestore(environment);
   if (!isRehydrated) {
     return <Loading />;
   }
  • Example of what happens when using the useQuery/QueryRenderer without useRestore:

  • Example of what happens when using the useQuery/QueryRenderer with useRestore:

    • the application shows a loading and does not render the useQuery component until it is rehydrated
    • if the application is online, the original policy is used and the execute of the QueryFetcher is performed
    • if the application is offline, the policy used will be store-only and the execute will look for the data in the store
  • Example of what happens when you use the useQuery/QueryRenderer without useRestore in SSR applications:

    • the first renderer is executed by setting the store-only policy
    • the store is not empty (having initialized the store with the data recovered from the server. The data recovered from the store will be displayed
    • the state is reconciled between the initial one (recovered from the server) and the state present in the storage, this makes a notification in the store that forces the updating of all the fragments subscribed
    • the restore is resolved (https://github.com/morrys/react-relay-offline/blob/master/src/hooks/useQueryOffline.ts#L59) and the forceUpdate is not executed as data are already displayed previously (priority is given to displaying data returned by status reconciliation)
  • In applications with SSR the useRestore should never be used

With the proposed change in relay-hooks, it will be possible to avoid using the useRestore as it will always be possible to perform a forced execution of the QueryFetcher.

Pass an `offline` prop to QueryRenderer render function.

Much like the cached: boolean prop is passed to the render function of the QueryRenderer, it would be useful to have a offline: boolean prop that indicates whether the environment is offline.

Although this can be done with environment.isOffline(), this means users depend on this being the same logic as is used by the lookupInStore function so they are bound to a specific version of this library.

Mutations Process

Hello,

I have a scenario that needs to be covered by our offline mutation solution and wanted to understand if the current implementation fits our needs.

We have the following requirements:

  1. Mutations should be persisted before they are executed to support eventual consistency.
  2. Mutations must be retried with original headers ( preserve multi-user devices )
  3. The original timestamp must also be sent to the server ( for conflict resolution ).

Just wondering if you can discuss a little detail on how this implementation stacks up to those requirements, and if not, what would need to be done for it be able to support them.

Look forward to the discussion.

Rob.

Typescript commitMutation type error.

commitMutation requires RelayModernEnvironment which is not compatible with the exported Environment from react-relay-offline implementation.

You can temporarily solve this by forcing Typescript to convert the type(obviously)

Include an implementation of fetchQuery to rehydrate store.

react-relay's fetchQuery function does not work well with the store, causing RelayRecordSourceMutator errors:

RelayRecordSourceMutator#create(): Cannot create a record with id 

To fix this, this library should implement a modified version of fetchQuery which rehydrates the store before making the query.

Something like this seems to do the job:

import { fetchQuery as relayFetchQuery } from 'react-relay-offline'

async function fetchQuery(...args) {
    const [environment] = args

    if (!environment.isRestored()) {
        await environment.restore()
    }

    return relayFetchQuery(...args)
}

release: v1.0.0

  • update dependency "react-relay >= 6.0.0"
  • update dependency "react: >=16.9.0"
  • possibility to use hooks (for now I add the dependency to relay-hooks and create useQueryOffline)
  • fix subscribe store-only & store-or-network #26
  • complete the SSR example in nextjs #23
  • rename the CACHE_FIRST policy in store-or-network
  • better management of the offline configuration morrys/wora#14
  • update dependency wora/cache-persist 2.0.4 (small fix)
  • release relay-hooks 2.0.0 relay-tools/relay-hooks#45

branch react-relay-offline: https://github.com/morrys/react-relay-offline/tree/relay-hooks
branch relay-hooks: https://github.com/relay-tools/relay-hooks/tree/2.0.0
wora: https://github.com/morrys/wora/

new release - supports netinfo 5.x

I tried to setup my relay environment in a react-native app by importing Environment, Store & RecordSource from react-relay-offline (no particular options). Now when I import QueryRenderer from react-relay-offline, I'm getting this error: Cannot read property 'fetch' of undefined

Seems to happen in OfflineFirst.js at this line :
this.promisesRestore = Promise.all([netinfo_1.NetInfo.isConnected.fetch(), this.offlineStore.restore()])

As far as I understand, the web implementation of NetInfo has a fetch function on isConnected but the native NetInfo doesn't have the same interface (anymore?).

offline node creation : use clientMutationId instead of id

Hi Morrys,

this is a bit of a question:

If I understood the documentation correct the client creating a new node (offline mutation) needs to provide the node id.

Is it possible to use the relay clientMutationId and let the backend decide on the final id?

environment.isRehydrated is not a function

There's something really strange going on here.

In standard react-relay the fetchQuery function that goes into the Network constructor has the following structure:

function fetchQuery(
  operation,
  variables,
  cacheConfig,
)

The fetchQuery that comes with react-relay-offline expects the following:

function fetchQuery(environment, taggedNode, variables, cacheConfig)

So what am I doing wrong here? It's something with the fetchQuery for sure, but it looks to me like your documentation is not complete (There's no clarity where fetchQuery is coming from).

source.getRecordIDs is not a function

Thanks for the amazing lib!

I've just tried upgrading from 0.10.0 -> 0.11.1. I'm using react-relay 5.0.0.

I'm now getting an error:

source.getRecordIDs is not a function

From RelayModernStore.

Any idea what this could be?

createFragmentContainer in v3

We've (finally) tried to upgrade to version 3. It seems we can no longer import createFragmentContainer from react-relay-offline. Has this now been completely removed?

I saw in the release notes that the Query HOC has been removed, but the fragment container is significantly harder for us to migrate off in one go (we'd have to refactor basically every component). Do we need to switch everything to hooks to upgrade to v3 (and hence relay 10)?

`retry` should check if environment is online.

Occasionally it is useful to have a "Try again" button when we go offline and do not have a cached version. This can be pressed by the user when they come back online in order to retry the query.

In order to do this, the retry prop (from the QueryRenderer) must be used. However, when the device is offline and QR is rendered, retry === null.

A better solution would be to check if the environment is online in every retry function, so that retry is never null. This would be used in useQuery.

For example, in getResult we could do:

if (environment.isOnline()) {
  renderProps.retry = () => {
    setHooksProps(execute(props.environment, props.query, props.variables));
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.