Skip to content

Pagination idea: type-specific refetching plugins #26

@stubailo

Description

@stubailo

In some sense, handling pagination in a smart way is just a special case of "when you ask for data, treat certain fields in a special way because we know that the arguments are meaningful." So if we're looking at a Relay spec paginated list:

// first fetch
{
  user {
    id
    name
    friends(first: 10) {
      edges {
        cursor
        node {
          id
          name
        }
      }
      pageInfo {
        hasNextPage
      }
    }
  }
}

// new query
... same stuff
friends(first: 20)

// second fetch, doesn't fetch all 20 but uses the existing information
... same stuff
friends(first: 10, after: "lastCursor")

Notice how easy it is for us as humans to imagine what data needs to be fetched to satisfy the new query.

Here's a set of hypotheses:

  1. The initial fetch doesn't need any up-front information about types or pagination - it can look at the query result to know what to do, as long as we inject __typename fields where necessary.
  2. The re-fetch can determine the new query by the information in the store, which now has type annotations and the arguments from the new query
  3. The transformation from (2) can be written as a pure function that can be injected into the apollo client and associated with certain type names

Basically, you could write a function and tell the apollo client:

"When refetching any field which refers to an object with a type matching this regular expression, give me the query you were going to fetch, and the contents of the store, and I'll give you a new query that says how to fetch the missing data."

So, for Relay pagination, you'd say:

client.registerPaginationPlugin(/.+Connection/, ({ state, id, selectionSet }) => {
  ... do work ...

  return {
    // as much of the result as can be found
    result,

    // if empty, then the cache is sufficient and result contains the data.
    // otherwise, an array of queries that need to be fetched
    missingSelectionSets, 
  }
});

Ideally this will allow plugging in to different pagination systems, as long as the paginated fields have predictable type names, for example *PaginatedList or Paginated*.

If we can do this, it will achieve some really nice effects:

  1. You don't necessarily need to use the Relay pagination spec, which can be hard to translate to some REST APIs
  2. The store can avoid being concerned with pagination if the API above is indeed sufficient

This is just a very ambitious idea, and I'm eager to determine if this very simple model can actually handle all cases of pagination and Relay connections in particular. More analysis to come soon.

@jbaxleyiii @helfer curious what you think about this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions