Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

fetchQuery results not being added to store cache #29

Open
matt-dalton opened this issue Oct 21, 2019 · 14 comments
Open

fetchQuery results not being added to store cache #29

matt-dalton opened this issue Oct 21, 2019 · 14 comments

Comments

@matt-dalton
Copy link

matt-dalton commented Oct 21, 2019

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?

@morrys
Copy link
Owner

morrys commented Oct 21, 2019

fetchQuery does not insert the record in the store but only in the recordsource. To insert a record in the Store it is necessary to manage the retain function of the environment.
This is the same behavior as react-relay.

@matt-dalton
Copy link
Author

Ahh gotcha. Does that mean there is no way to default to loading these values from the cache? And you can only use withQueryRenderer results offline?

@morrys
Copy link
Owner

morrys commented Oct 21, 2019

fetchQuery data is deleted after the garbage collector is run ...

@sibelius can you indicate where the retain function is documented and how it should be used in combination with the fetchQuery?

@matt-dalton
Copy link
Author

matt-dalton commented Oct 22, 2019

Interesting. I've been playing about with this, and see that you can write something like

import { createOperationDescriptor, getRequest } from 'relay-runtime'

const operation = createOperationDescriptor(getRequest(query))
data = await fetchQuery(relayEnv.environment, query)
relayEnv.environment.retain(operation.root)

and then I see data is retained in the store.

Problem is, I then want to be able to fallback to the cache data if I'm offline, which is what the react-relay-offline QueryRenderer does nicely. Is there a way using the library of replicating this logic?

I tried using relayEnv.environment.lookup(operation.fragment, operation).data but this seems to return undefined

@morrys
Copy link
Owner

morrys commented Oct 22, 2019

I can't understand your use case, it looks like you're completely recreating the queryrenderer

@matt-dalton
Copy link
Author

I'd like to be able to do exactly that - recreate the use-cache-if-offline functionality from the query renderer but using the imperative fetchQuery. Is there a reason why this is a bad idea?

@morrys
Copy link
Owner

morrys commented Oct 22, 2019

Not necessarily a bad idea, I'm curious about how you're using the library / offline to see if there's anything to improve in react-relay-offline or recommend other solutions.

relayEnv.environment.lookup (operation.fragment, operation) .data should be the correct way to retrieve information from the store.
If it returns the value null it means that not all the data necessary to the query are present.

@morrys
Copy link
Owner

morrys commented Oct 22, 2019

You seem to be dealing with the same theme as my example project: https://github.com/morrys/offline-examples/blob/master/relay/nextjs/relay/withData.tsx

@sibelius
Copy link
Collaborator

This use case is possible with new relay hooks on experimental package

@matt-dalton
Copy link
Author

I'm curious about how you're using the library / offline to see if there's anything to improve in react-relay-offline or recommend other solutions.

Our use case: We have one app query that we run imperatively using fetchQuery. The rest of the app now works nicely offline, and would be nice to have the same offline logic here (i.e. if offline get from cache)

As a new user to this library I would have expected the lib's fetchQuery to work the same way as QueryRenderer in this sense. But now the different behaviour seems like more of a Relay quirk, so can see why you haven't implemented it.

This use case is possible with new relay hooks on experimental package

Cool thanks. What specifically will this be addressing @sibelius - adding imperative requests to the cache by default?

@morrys
Copy link
Owner

morrys commented Oct 23, 2019

I imagine that fetchQuery is not supposed to manage the Store as it is a direct request on the network.

What seems strange to me is that the lookup gives null.

For your use case the correct procedure is as follows:

online: fetchQuery, retain
unmount component: dispose retain
offline: lookup in the store

Obviously the lookup returns null when the garbage collector has eliminated the references in the store.

During the offline state the garbage collector is disabled.

@matt-dalton
Copy link
Author

OK cool - well good to know I was on the right lines. Perhaps there's something I've done wrong - will keep looking. Thanks!

@octodhruv
Copy link

I imagine that fetchQuery is not supposed to manage the Store as it is a direct request on the network.

What seems strange to me is that the lookup gives null.

For your use case the correct procedure is as follows:

online: fetchQuery, retain
unmount component: dispose retain
offline: lookup in the store

Obviously the lookup returns null when the garbage collector has eliminated the references in the store.

During the offline state the garbage collector is disabled.

Hi morrys, I've also been following this issue, and I was wondering that wouldn't the unmount dispose retain stop the values from being persisted offline, as we're clearing the store? Could you please expand on this a little more?

Thanks!

@morrys
Copy link
Owner

morrys commented Nov 6, 2019

hi @octodhruv,
I try to answer but maybe I didn't understand your question well.

It is necessary to make the dispose to allow the garbage collector to clean the store and avoid growing keeping invalid data.

In react-relay-offline I added the TTL in the queries and a default value for all the queries that are executed (10 minutes). This means that even if a query has been disposed, the garbage collector does not delete it until the TTL expires.

Furthermore, when the application is offline I disabled the garbage collector.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants