Urql: relayPagination and network-only

Created on 26 Mar 2020  Â·  13Comments  Â·  Source: FormidableLabs/urql

Hi All

I have the following query

query FriendsQuery($after: String!) {
  me {
    id
    friends(after: $after) {
      edges {
        node {
          ...FriendshipFragment
        }
      }
      pageInfo {
        endCursor
        hasNextPage
      }
    }
  }
}

And the following hook

export const useFriends = () => {
  const client = useClient();
  const [{ fetching, error, data }] = useQuery<
    FriendsQueryQuery,
    FriendsQueryQueryVariables
  >({
    query: FRIENDS_QUERY,
    requestPolicy: "network-only",
    variables: {
      after: "",
    },
  });

  const friends =
    data === undefined ? undefined : data?.me?.friends ?? undefined;

  const fetchMore = React.useCallback(
    (cursor: string) => {
      return client
        .query<FriendsQueryQuery, FriendsQueryQueryVariables>(
          FRIENDS_QUERY,
          { after: cursor },
          { requestPolicy: "network-only" }
        )
        .toPromise();
    },
    [client]
  );

  return React.useMemo(
    () => ({
      fetching,
      error,
      friends,
      fetchMore,
    }),
    [fetching, error, friends, fetchMore]
  );

Results are merged using relayPagination

resolvers: {
  User: {
    friends: relayPagination()
  }
}

I have a component that does an infinite scrolling and shows all my friends.

When the component is unmounted and afterwards remounted i would like to fetch again the lists of friends (hence the network-only)

The problem is that due to the relay pagination the friends variable contains all the friends fetched from the previous mount with pageInfo.hasNextPage === false.

The only request that is requested again is the initial with after === ""

Thanks

Most helpful comment

As for the very specific, I dont think i am the only person who want to use relayPagination with cache-and-network || network-only

All 13 comments

I think the problem relies in the pageInfo of relayPagination. It always sets it to the results of the last page even though after the remount i have refetched the first page.

I am not sure if its wise to reset pageInfo to the currently fetched page results

Hey Zenios,

Good question but this isn't really the use case of a resolver, for us it would be impossible (and a waterfall) to refetch it all.

Let me explain, if we would refetch your first page we can't eagerly refetch your second page, we would have to check the pageInfo of your first response to go for your second one and so son.

The better solution for this situation would be to make a custom hook:

const useRevalidatingPagination = () => {
  const [list, setList] = useState([])

  const [data] = useQuery(query);

  useEffect(() => {
    if we go from fethcing to not fetching 
      addToList
  }, [data]);

  return list;
}

So now we have a list that resets every time you navigate back, when you query you will receive the result with a stale flag so you can wait until it gets revalidated.

I dont expect urql to refetch all.

What i expect though is once the results are merged via relayPagination pageInfo should show the latest updated pageInfo not the last fetched from the previous results.

TO be more clear

Fetch page 1 results should be edges:[...page1] pageInfo:page1PageInfo

Fetch page 2 results should be edges:[...page1,...page2] pageInfo:page2PageInfo

Unmount / remoount and network only

Fetch page 1 results should be edges[...page1,...page2] pageInfo:page1PageInfo

while know its page2PageInfo

Hope its clear

The pageInfo is merged like all the pages are, so it'll appropriately merge the beginning and end bits.

Because you can fetch pages in "both directions" (after / before) we account for that and create a new pageInfo based on that. https://github.com/FormidableLabs/urql/blob/51ae6806a6adf5a9fc7f17c43ca2dbe066f9c9c3/exchanges/graphcache/src/extras/relayPagination.ts#L200-L214

So it will follow the logic you're describing, but unmount/remount is not what you're expecting here. Instead the result is identical no matter what page you ask for currently. We're thinking of maybe filtering it down, but that'd be an additional option on the resolver.

That being said even if you ask for the "first page" you'll get a result based on _all the pages_ that Graphcache knows about.

That is understood but the way relayPagination is structtured right now there is no way once the whole list is fetched to refetch it (Throughout the whole applications lifecycle)

Lets take facebook for example. If i view friends list once then go to another page and go back to friends list the full cycle is executed from the beginning while us with relayPagination i cannot do that because it always points to the last pages info

You could try to write a resolver that's _similar_ to relayPagination, I suppose, that is more strict. So you could _walk_ the pages in the cache using pageInfo explicitly (by using endCursor as the input for after for instance) which means that if you refetch (using network-only or cache-and-network) the chain of pages can be broken by an earlier page changing.

The problem is that i didnt find a way to know which page was the last refreshed / fetched

I don't think you'll ever have to check which page was last fetched. The resolver just needs to get the requested page for your use-case and then "walk backwards" (so use the input arguments e.g. use the after cursor and find the page that has endCursor set to that).

When you're missing a page you can set info.partial = true to fetch the other pages. And when you don't have your current page you can either return the previous ones and set partial or just return undefined for a cache miss.

Thanks a lot

@zenios I’ll think about how much sense it makes to integrate this into the relayPagination helper btw 😇 it may just be very specific 😅

Think about it.my only concern is what i said before.once you use relay
pagination forget about refreshing. You have to hack your way around it

On Fri, 27 Mar 2020, 02:03 Phil Plückthun, notifications@github.com wrote:

@zenios https://github.com/zenios I’ll think about how much sense it
makes to integrate this into the relayPagination helper btw 😇 it may
just be very specific 😅

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/FormidableLabs/urql/issues/672#issuecomment-604747414,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAAV3YMWKPNFEBPNXPNGEVLRJPUNVANCNFSM4LUQKTKA
.

As for the very specific, I dont think i am the only person who want to use relayPagination with cache-and-network || network-only

Was this page helpful?
0 / 5 - 0 ratings

Related issues

andyrichardson picture andyrichardson  Â·  4Comments

frederikhors picture frederikhors  Â·  3Comments

davidhouweling picture davidhouweling  Â·  4Comments

ivosequeros picture ivosequeros  Â·  5Comments

tgrecojs picture tgrecojs  Â·  4Comments