facebook / facebook/relay

components with deferred fragment data do not suspend when loadNext is called on a connection

Open
#4,803 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
19k
Forks
1.9k
PR merge metrics
No merged PRs in 30d

Description

We have a table component where fragments for individual cells are deferred with the `@defer` directive. On the initial load of the table, we see these cells suspend and fall back to their parent suspense boundary's fallback value. However, on calls to the `loadNext` function returned by `usePaginationFragment`, we see these cells render and the call to `useFragment` reads `undefined` rather than causing the component to suspend. However, using the `refetch` function returned by `usePaginationFragment` I do see the cells with the deferred fragment suspend successfully.

Below is a simplified example of the components and fragments I'm working with when experiencing this behavior:

```
import React from 'react';
import { usePreloadedQuery, graphql } from 'react-relay';

import { EntryPointComponentProps } from 'data-router';
import { Box, Heading, Separator, Table, Button } from 'shared-components';

import { DeferredPaginationPageReferenceMfeQuery } from './__generated__/DeferredPaginationPageReferenceMfeQuery.graphql';
import { PaginationTableReferenceMfe_company$key as CompanyFragmentKey } from './__generated__/PaginationTableReferenceMfe_company.graphql';
import { TableRowReferenceMfe_journey$key as JourneyFragmentKey } from './__generated__/TableRowReferenceMfe_journey.graphql';
import { DeferredTableCellReferenceMfe_journey$key as JourneyFragmentKey } from './__generated__/DeferredTableCellReferenceMfe_journey.graphql';

type Props = EntryPointComponentProps<{
query: DeferredPaginationPageReferenceMfeQuery;
}>;

const DeferredPaginationPage = ({ queries }: Props) => {
const data = usePreloadedQuery(
graphql`
query DeferredPaginationPageReferenceMfeQuery($companyId: ID!, $first: Int!, $after: String)
@raw_response_type {
company: node(id: $companyId) {
... on Company {
...PaginationTableReferenceMfe_company
...RefetchTableReferenceMfe_company
}
}
}
`,
queries.query
);
if (data.company) {
return (

Does pagination work with defer?





);
}

return

something is horribly wrong
;
};

const PaginationTable = ({
companyFragmentKey,
}: {
companyFragmentKey: CompanyFragmentKey;
}) => {
const { data, loadNext, refetch } = usePaginationFragment(
graphql`
fragment PaginationTableReferenceMfe_company on Company
@refetchable(queryName: "PaginationTableReferenceMfe_company_refetchable") {
journeys(first: $first, after: $after)
@connection(key: "PaginationTableReferenceMfe_company_journeys") {
edges {
cursor
node {
id
...TableRowReferenceMfe_journey
}
}
totalCount
}
}
`,
companyFragmentKey
);

return (



internal ID
name
messagesSent


{data.journeys?.edges.map((j) => (

))}




loadNext(1)}>Load next

refetch({
first: 1,
after: data.journeys?.edges[data.journeys?.edges.length - 1].cursor,
})
}
>
Refetch


);
};

const TableRow = ({ journeyFragmentKey }: { journeyFragmentKey: JourneyFragmentKey }) => {
const data = useFragment(
graphql`
fragment TableRowReferenceMfe_journey on Journey {
internalId
name
...DeferredTableCellReferenceMfe_journey
@defer(label: "TableRowReferenceMfe_journey_deferred_cell")
}
`,
journeyFragmentKey
);

return (

{data.internalId}
{data.name}




);
};

const DeferredTableCell = ({
journeyFragmentKey,
}: {
journeyFragmentKey: JourneyFragmentKey;
}) => {
const data = useFragment(
graphql`
fragment DeferredTableCellReferenceMfe_journey on Journey {
stats {
messagesSent
}
}
`,
journeyFragmentKey
);
console.log(data);
return {data.stats?.messagesSent};
};
```

example responses from queries fired by our calls to load query, load next, and refetch are below

load query:
```
--END_OF_PART
Content-Type: application/json

{"hasNext":true,"data":{"company":{"__typename":"Company","journeys":{"edges":[{"cursor":"MjAyMy0wOS0wOVQwMzoxODozNy43ODQxOTha","node":{"id":"MDc6Sm91cm5leTE4MDg2","internalId":"18086","name":"Roger Test Stat","__typename":"Journey"}}],"totalCount":5715,"pageInfo":{"endCursor":"MjAyMy0wOS0wOVQwMzoxODozNy43ODQxOTha","hasNextPage":true}},"id":"MDc6Q29tcGFueTU"}},"extensions":{"traceId":"3936810731304619923"}}
--END_OF_PART
Content-Type: application/json

{"hasNext":true,"incremental":[{"data":{"stats":{"messagesSent":31}},"label":"TableRowReferenceMfe_journey$defer$TableRowReferenceMfe_journey_deferred_cell","path":["company","journeys","edges",0,"node"]}]}
--END_OF_PART
Content-Type: application/json

{"hasNext":false}
--END_OF_PART--
```

load next:
```
--END_OF_PART
Content-Type: application/json

{"hasNext":true,"data":{"node":{"__typename":"Company","journeys":{"edges":[{"cursor":"MjAyNC0wMi0xMlQxODo0MDozNi41NzE3NDZa","node":{"id":"MDc6Sm91cm5leTMzMTMz","internalId":"33133","name":"Order Shipped 02-12-24 18:40:36","__typename":"Journey"}}],"totalCount":5715,"pageInfo":{"endCursor":"MjAyNC0wMi0xMlQxODo0MDozNi41NzE3NDZa","hasNextPage":true}},"id":"MDc6Q29tcGFueTU"}},"extensions":{"traceId":"3214458784753263795"}}
--END_OF_PART
Content-Type: application/json

{"hasNext":true,"incremental":[{"data":{"stats":{"messagesSent":0}},"label":"TableRowReferenceMfe_journey$defer$TableRowReferenceMfe_journey_deferred_cell","path":["node","journeys","edges",0,"node"]}]}
--END_OF_PART
Content-Type: application/json

{"hasNext":false}
--END_OF_PART--
```

refetch:
```
--END_OF_PART
Content-Type: application/json

{"hasNext":true,"data":{"node":{"__typename":"Company","journeys":{"edges":[{"cursor":"MjAyNC0wOC0yNlQyMzoyNzoyMC4wODkwNDVa","node":{"id":"MDc6Sm91cm5leTc3OTI5","internalId":"77929","name":"Some added to cart","__typename":"Journey"}}],"totalCount":5715,"pageInfo":{"endCursor":"MjAyNC0wOC0yNlQyMzoyNzoyMC4wODkwNDVa","hasNextPage":true}},"id":"MDc6Q29tcGFueTU"}},"extensions":{"traceId":"1116799166867392896"}}
--END_OF_PART
Content-Type: application/json

{"hasNext":true,"incremental":[{"data":{"stats":{"messagesSent":0}},"label":"TableRowReferenceMfe_journey$defer$TableRowReferenceMfe_journey_deferred_cell","path":["node","journeys","edges",0,"node"]}]}
--END_OF_PART
Content-Type: application/json

{"hasNext":false}
--END_OF_PART--
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.