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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MissingFieldError] - Dangling reference to missing... #6962

Closed
tafelito opened this issue Sep 2, 2020 · 4 comments
Closed

[MissingFieldError] - Dangling reference to missing... #6962

tafelito opened this issue Sep 2, 2020 · 4 comments

Comments

@tafelito
Copy link

tafelito commented Sep 2, 2020

Intended outcome:

I'm get the MissingFieldError Dangling reference to missing... warning but I think in this case is not correct.

I have a query that fetches an item by id. The query uses fetchPolicy: 'cache-first' nextFetchPolicy: 'cache-only' and returnPartialData: true

const { data, error, loading } = useRecordQuery({
    variables: {
      id: queryId,
    },
    fetchPolicy: 'cache-first',
    nextFetchPolicy: 'cache-only',
    returnPartialData: true,
  });

then I have a typePolicy for the field like this

records_by_pk(existing, { args, toReference }) {
  return (
    existing ||
    toReference({
      __typename: 'records',
      id: args?.id,
    })
  );
},

The reason I use that typePolicy is to prevent a network request in case the record already exists. So if I go to the list records and then to a specific record this works as intended.

Now the warning happens when going directly to the details page, without querying the list first.

Because I use returnPartialData: true the query returns an empty record {record: {}}.

Actual outcome:

I believe in this case the warning is incorrect and it shouldn't show up, am I mistaken? Should I need to filter the empty record in the typePolicy if there is not data present?

Versions

  System:
    OS: macOS 10.15.6
  Binaries:
    Node: 14.9.0 - /usr/local/bin/node
    Yarn: 1.22.5 - /usr/local/bin/yarn
    npm: 6.14.7 - /usr/local/bin/npm
  Browsers:
    Chrome: 85.0.4183.83
    Safari: 13.1.2
  npmPackages:
    @apollo/client: 3.1.4 => 3.1.4 
    @apollo/link-context: ^2.0.0-beta.3 => 2.0.0-beta.3 
    @apollo/link-error: ^2.0.0-beta.3 => 2.0.0-beta.3 
    apollo-upload-client: ^13.0.0 => 13.0.0 
  npmGlobalPackages:
    apollo-codegen: 0.20.2
@tafelito
Copy link
Author

tafelito commented Sep 9, 2020

To add some more context to this

I don't really think that returnPartialData has anything to do with this

When debugging this, I found that the problem is actually when evicting the item by id

What happens is, after the evict, because the details query has a nextFetchPolicy: 'cache-only', the query will re run again, and since there is a typePolicy for the details query, it's returning the reference to an object that actually does not exist in the cache, hence the warning

To prevent this warning from happening, it can be filtered using the canRead fn like this.

item_by_id(existing, { args, toReference, canRead }) {
  if (existing) {
    return existing;
  }
  const ref = toReference({
    __typename: 'records',
    id: args?.id,
  });
  if (!canRead(ref)) {
    return;
  }
  return ref;
},

I still think that it would be best to solve this, in my case, if I could make the evict to not broadcast the change, even if the fetchPolicy is cache-only

@KeithGillette
Copy link
Contributor

@tafelito, Is that a TypePolicy custom read function? Does it actually "filter out" the invalid Reference or just return undefined instead of the Reference?

I'm encountering a similar issue on a watchQuery with the same Fetch Policies (though not returnPartialData: true) after using cache.evict on the underlying object. I'm not sure how to not broadcast the eviction to this particular query or complete its subscription.

@tafelito
Copy link
Author

AC has changed many times since v3 in terms of they way it behaves and warnings/errors that it gives when working with the cache. I've been jumping from version to version just to find a pattern that actually works for me and but I found that there is never a a right way of doing things. it's probably also my fault to always try to keep up to date with every release so I understand that this can happen specially when it comes to OSS.

Now having said that, I'm putting together an example of what I think is a very common pattern iterating with the cache when using offset/limit style pagination. I will open a new issue and put this as a reference

to your question @KeithGillette, I tried 3 different ways of doing that and all depends on the use case but most of the time just using this as a typePolicy works. Is not a read function, is just a typePolicy for the Query fields

Query: {
    fields: {
      records_by_pk(existing, { args, toReference }) {
        return (
          existing ||
          toReference({
            __typename: 'records',
            id: args?.id,
          })
        );
      },
    }
}

Another way is to filter check if exists, if check if is readable, and if not return the ref. When you return undefined means its' gonna try to fetch from the server (depending on the fetchPolicy of course)

      records_by_pk(existing, { args, toReference, canRead }) {
        if (existing) {
          return existing;
        }
        const ref = toReference({
          __typename: 'records',
          id: args?.id,
        });
        if (!canRead(ref)) {
          return;
        }
        return ref;
      },

and finally sometimes you also want to check if even the existing is readable and if not return a ref in case it exists

      records_by_pk(existing, { args, toReference, canRead }) {
        return canRead(existing)
          ? existing
          : toReference({ __typename: 'records', id: args?.id });
      },

In terms of broadcasting, I was never able to make the broadcast arg to work when doing an eviction, if that's what you meant. It's supposed to broadcast to all watchable queries by default unless you set it to false, but in my case that never worked and that's what I will try to show in the example I'm putting together

@hwillson
Copy link
Member

We'll need a reproduction (using @apollo/client@latest) to be able to troubleshoot this further. Thanks!

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants