Skip to content

Add createPagination and createInfinityScroll fabrics #332

@Bricks666

Description

@Bricks666

Problems and use-cases

Problems
Pagination and infinite scroll are common queries used a lot and mostly need a typical units for storing page, next parameters and etc. So This API will solve these problems make work with queries such types easier.

'Cause this PR is big, I split it on two parts. This one is about pagination. The second will be after this.

Use cases
Common use-case it's flow where the page is identified by a number and the next(previous) also can be requested with page number, not link received from server. Pagination by server sent link may be classified as edge-case, 'cause it's not very popular, but sometimes used.

Analysis, pros, cons and pitfalls

Analysis
I researched several libs/packages provided queries and looked at their pagination receipts.

The first group contains SWR, @tanstack/query and RTK-Query. All them don't provide special methods for pagination. It makes queries more flexible, but more times makes us write the same code.
If try to find a reason for such decisions, I can guess that SWR and @tanstack/query were designed so for integration with view frameworks and managing from them.

The second group now contains only effector-pagination. This lib implement pagination fabric using effector units. This fabric manage current page, possibility to make request and caching. I think main pros it's encapsulation of change page logic and predicates of possibility fetch next and prev page.

Suggested implementation, compatibility with others APIs

I suggest to make pagination as extended type of Query. This will allow us to integrate pagination with keepFresh, retry and cache without much problems, 'cause it will be query with some extra fields and methods.

Interface may look like:

interface Pagination<Params extends RequiredPageParams, Data, Error, InitialData = null> extends Query<Params, Data, Error, InitialData> {
    $page: Store<number>;
    $hasNext: Store<boolean>;
    $hasPrev: Store<boolean>;
    next: Event<void>;
    prev: Event<void>;
    specific: Event<RequiredPageParams>;
}

And using like that:

import { createPagination } from "@farfetched/core";

const pagination = createPagination(...)

pagination.start({ ..., page: 1 }) // Request 1th page
pagination.next() // Request 2th page
pagination.prev() // Request 1th page again 
pagination.specific({ page: 43 }) // Request 43th page

Restrictions

  1. Params of passed handler/effect should extend RequiredPageParams interface which provides requested page and limit of requested items.
  2. How to determine the end of pagination? We may restrict shape of mapData response and make this function required.
    Function may return object like this:
interface MapDataShape<Data> {
   data: Data;
   currentPage: number;
   hasNextPage: boolean;
   // Or change field on totalPages: number;
   hasPrevPage: boolean;
}

And then this object will be split filed to store.

  1. Base params(params passed into start method) will be used for next requests(next, prev, specific) with overriding page prop. But if user want to change one of it(even offset) he will need to call start method again. Base params will be got from $latestParams. Also user can't to fetch next and others pagination method if there're not $latestParams
  2. This implementation doesn't support pagination depended on server sent links at all. But cover the most popular cases with number pagination.

Pagination now

The first written in official example of farfetched and provide query with some stores for storing pages.
I've not found any more.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions