EntityStore: proper pagination support
This commit is contained in:
@ -29,6 +29,10 @@ export const getNextLink = (response: AxiosResponse): string | undefined => {
|
||||
return getLinks(response).refs.find(link => link.rel === 'next')?.uri;
|
||||
};
|
||||
|
||||
export const getPrevLink = (response: AxiosResponse): string | undefined => {
|
||||
return getLinks(response).refs.find(link => link.rel === 'prev')?.uri;
|
||||
};
|
||||
|
||||
const getToken = (state: RootState, authType: string) => {
|
||||
return authType === 'app' ? getAppToken(state) : getAccessToken(state);
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { Entity } from './types';
|
||||
import type { Entity, EntityListState } from './types';
|
||||
|
||||
const ENTITIES_IMPORT = 'ENTITIES_IMPORT' as const;
|
||||
const ENTITIES_FETCH_REQUEST = 'ENTITIES_FETCH_REQUEST' as const;
|
||||
@ -23,20 +23,22 @@ function entitiesFetchRequest(entityType: string, listKey?: string) {
|
||||
};
|
||||
}
|
||||
|
||||
function entitiesFetchSuccess(entities: Entity[], entityType: string, listKey?: string) {
|
||||
function entitiesFetchSuccess(entities: Entity[], entityType: string, listKey?: string, newState?: EntityListState) {
|
||||
return {
|
||||
type: ENTITIES_FETCH_SUCCESS,
|
||||
entityType,
|
||||
entities,
|
||||
listKey,
|
||||
newState,
|
||||
};
|
||||
}
|
||||
|
||||
function entitiesFetchFail(entityType: string, listKey?: string) {
|
||||
function entitiesFetchFail(entityType: string, listKey: string | undefined, error: any) {
|
||||
return {
|
||||
type: ENTITIES_FETCH_FAIL,
|
||||
entityType,
|
||||
listKey,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { getNextLink, getPrevLink } from 'soapbox/api';
|
||||
import { useApi, useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import { importEntities } from '../actions';
|
||||
import { entitiesFetchFail, entitiesFetchRequest, entitiesFetchSuccess } from '../actions';
|
||||
|
||||
import type { Entity } from '../types';
|
||||
|
||||
type EntityPath = [entityType: string, listKey: string]
|
||||
|
||||
function useEntities<TEntity extends Entity>(path: EntityPath, url: string) {
|
||||
function useEntities<TEntity extends Entity>(path: EntityPath, endpoint: string) {
|
||||
const api = useApi();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
@ -32,26 +33,38 @@ function useEntities<TEntity extends Entity>(path: EntityPath, url: string) {
|
||||
const hasNextPage = Boolean(list?.state.next);
|
||||
const hasPreviousPage = Boolean(list?.state.prev);
|
||||
|
||||
const fetchEntities = async() => {
|
||||
const { data } = await api.get(url);
|
||||
dispatch(importEntities(data, entityType, listKey));
|
||||
};
|
||||
|
||||
const fetchNextPage = async() => {
|
||||
const next = list?.state.next;
|
||||
|
||||
if (next) {
|
||||
const { data } = await api.get(next);
|
||||
dispatch(importEntities(data, entityType, listKey));
|
||||
const fetchPage = async(url: string): Promise<void> => {
|
||||
dispatch(entitiesFetchRequest(entityType, listKey));
|
||||
try {
|
||||
const response = await api.get(url);
|
||||
dispatch(entitiesFetchSuccess(response.data, entityType, listKey, {
|
||||
next: getNextLink(response),
|
||||
prev: getPrevLink(response),
|
||||
fetching: false,
|
||||
error: null,
|
||||
}));
|
||||
} catch (error) {
|
||||
dispatch(entitiesFetchFail(entityType, listKey, error));
|
||||
}
|
||||
};
|
||||
|
||||
const fetchPreviousPage = async() => {
|
||||
const fetchEntities = async(): Promise<void> => {
|
||||
await fetchPage(endpoint);
|
||||
};
|
||||
|
||||
const fetchNextPage = async(): Promise<void> => {
|
||||
const next = list?.state.next;
|
||||
|
||||
if (next) {
|
||||
await fetchPage(next);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchPreviousPage = async(): Promise<void> => {
|
||||
const prev = list?.state.prev;
|
||||
|
||||
if (prev) {
|
||||
const { data } = await api.get(prev);
|
||||
dispatch(importEntities(data, entityType, listKey));
|
||||
await fetchPage(prev);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import {
|
||||
} from './actions';
|
||||
import { createCache, createList, updateStore, updateList } from './utils';
|
||||
|
||||
import type { Entity, EntityCache } from './types';
|
||||
import type { Entity, EntityCache, EntityListState } from './types';
|
||||
|
||||
enableMapSet();
|
||||
|
||||
@ -22,14 +22,19 @@ const importEntities = (
|
||||
entityType: string,
|
||||
entities: Entity[],
|
||||
listKey?: string,
|
||||
newState?: EntityListState,
|
||||
): State => {
|
||||
return produce(state, draft => {
|
||||
const cache = draft.get(entityType) ?? createCache();
|
||||
cache.store = updateStore(cache.store, entities);
|
||||
|
||||
if (listKey) {
|
||||
const list = cache.lists.get(listKey) ?? createList();
|
||||
cache.lists.set(listKey, updateList(list, entities));
|
||||
let list = cache.lists.get(listKey) ?? createList();
|
||||
list = updateList(list, entities);
|
||||
if (newState) {
|
||||
list.state = newState;
|
||||
}
|
||||
cache.lists.set(listKey, list);
|
||||
}
|
||||
|
||||
return draft.set(entityType, cache);
|
||||
@ -59,8 +64,9 @@ const setFetching = (
|
||||
function reducer(state: Readonly<State> = new Map(), action: EntityAction): State {
|
||||
switch (action.type) {
|
||||
case ENTITIES_IMPORT:
|
||||
case ENTITIES_FETCH_SUCCESS:
|
||||
return importEntities(state, action.entityType, action.entities, action.listKey);
|
||||
case ENTITIES_FETCH_SUCCESS:
|
||||
return importEntities(state, action.entityType, action.entities, action.listKey, action.newState);
|
||||
case ENTITIES_FETCH_REQUEST:
|
||||
return setFetching(state, action.entityType, action.listKey, true);
|
||||
case ENTITIES_FETCH_FAIL:
|
||||
|
||||
Reference in New Issue
Block a user