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

Connection Fields in Query are parsed to undefined even though network response has data in those fields #4875

Open
KieranTH opened this issue Jan 9, 2025 · 3 comments

Comments

@KieranTH
Copy link

KieranTH commented Jan 9, 2025

Hooks used

  • useLazyLoadQuery
  • usePaginationFragment

Versions

  • React: 19.0.0-rc-66855b96-20241106
  • React-Relay: 18.2.0

Issue Description

When using loadNext from the usePaginationFragment hook, connection fields are parsed as undefined - But in the network response exist correctly.

Any data fetched initially is correctly structured via the Server response - this only happens with PAGINATED data.

This seems to be a regression after updating to the latest version of Relay. This setup was working previously.

I've been able to narrow down one of the triggers for it.

If i have a connection like friends(), if i add a VARIABLE of first - the bug appears.

Error:
friends(first: $friendsFirst)

Works:
friends(first: 20)

Example of Data

Retrieved from Server:

{
  "id": "123",
  "friends": { "edges": [] }
}

Returned from usePaginationFragment:

{
  "id": "123",
  "friends": undefined
}

Example of Query

Wrapper Query:

query HomeQuery($first: Int = 20, $cursor: Cursor, $where: WhereInput = {}, ...bunchOfArgs){
   ...HomeFragment @arguments(first: $first, cursor: $cursor, where: $where, ...bunchOfArgs: $...bunchOfArgs)
 }

Fragment:

fragment HomeFragment on Query
  @argumentDefinitions(
    first: { type: "Int", defaultValue: 20 }
    cursor: { type: "Cursor" }
    where: { type: "WhereInput", defaultValue: {} }
    ...bunchOfArgsDefs
  )
  @refetchable(queryName: "HomePaginationQuery") {
    objects(first: $first, after: $cursor, where: $where) 
    @connection(key: "HomeConnection_objects", filters: ["where"]){
      edges {
        node {
          id
          friends(first: 20 # Changing this to a variable causes the bug to appear){
            edges {
               node {
                  id
               }
            }
          }
        }
      }
    }
  }
@itamark
Copy link
Contributor

itamark commented Jan 9, 2025

@KieranTH do you have the full response payload to share for the loadNext that parsed to undefined? Including

{
    data: {}, 
    errors: [] // (if any errors exist)
} 

@KieranTH
Copy link
Author

KieranTH commented Jan 9, 2025

@KieranTH do you have the full response payload to share for the loadNext that parsed to undefined? Including

{
    data: {}, 
    errors: [] // (if any errors exist)
} 

There are no errors in response by the backend.

The response looks something like this:

{
 data: {
   objects: {
     edges: [
       {
          node: {
             "id": "123",
             "friends": { "edges": [] }
          }
       }
     ]
   }
 }
}

I've actually been able to narrow it down fully.

When a default value isn't given to the first variable IN THE WRAPPER QUERY, the bug appears.

BROKEN:

HomeQuery($first: Int = 20, $cursor: Cursor, $where: WhereInput = {}, $friendFrist: Int)

WORKING:

HomeQuery($first: Int = 20, $cursor: Cursor, $where: WhereInput = {}, $friendFirst: Int = 20)

Even though I have a default set in the Fragment Arguments:

{
friendFirst: {type: "Int", defaultValue: 20}
}

Any ideas why this could cause such weird behaviour?

@captbaritone
Copy link
Contributor

Interesting. Thanks for the report. So, if I understand correctly, the bug triggers when:

  1. The first argument to your connection field is provided by a fragment variable with a default value provided (first: { type: "Int", defaultValue: 20 }
  2. You are passing the fragment to the query using a query variable that does not have a default value
  3. You make an initial query (With what variables passed?)
  4. You paginate (with no variables passed?)

If all these things are true, you end up with "friends": undefined in your component?

I'm a little confused by the inclusion of $first and $firstFriend and how they actually fit together in the real example.

Cache keys in the store are computed based on a field's name as well as a serialized form of the variables passed to that field. I suspect there's some disagreement between one or more of:

  1. RelayResponseNormalizer (which uses the generated artifact for the query)
  2. Connection handler
  3. RelayReader (which uses the generated artifact for the fragment).

Perhaps somehow this combination of variables/defaults triggers a bug where they end up computing different cache keys? A snapshot of what's in the store before/after you issue the pagination query might help us understand what's gone wrong here.

The next step here would be to create a reproduction of the issue as a test. Probably following the examples given here: https://github.com/facebook/relay/blob/main/packages/react-relay/relay-hooks/__tests__/usePaginationFragment-test.js

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

3 participants