From cb8363d179ff6221f98030fd34daef4df7876209 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 22 Mar 2023 18:47:10 -0500 Subject: [PATCH] EntityStore: make fetching the first page override the old list --- .../entity-store/__tests__/reducer.test.ts | 41 ++++++++++++++++++- app/soapbox/entity-store/actions.ts | 9 +++- app/soapbox/entity-store/hooks/useEntities.ts | 6 +-- app/soapbox/entity-store/reducer.ts | 12 +++++- 4 files changed, 61 insertions(+), 7 deletions(-) diff --git a/app/soapbox/entity-store/__tests__/reducer.test.ts b/app/soapbox/entity-store/__tests__/reducer.test.ts index 4b5a9752de..f43150b685 100644 --- a/app/soapbox/entity-store/__tests__/reducer.test.ts +++ b/app/soapbox/entity-store/__tests__/reducer.test.ts @@ -3,6 +3,7 @@ import { dismissEntities, entitiesFetchFail, entitiesFetchRequest, + entitiesFetchSuccess, importEntities, } from '../actions'; import reducer, { State } from '../reducer'; @@ -88,6 +89,44 @@ test('failure adds the error to the state', () => { expect(result.TestEntity!.lists.thingies!.state.error).toBe(error); }); +test('import entities with override', () => { + const state: State = { + TestEntity: { + store: { '1': { id: '1' }, '2': { id: '2' }, '3': { id: '3' } }, + lists: { + thingies: { + ids: new Set(['1', '2', '3']), + state: { ...createListState(), totalCount: 3 }, + }, + }, + }, + }; + + const entities: TestEntity[] = [ + { id: '4', msg: 'yolo' }, + { id: '5', msg: 'benis' }, + ]; + + const now = new Date(); + + const action = entitiesFetchSuccess(entities, 'TestEntity', 'thingies', { + next: undefined, + prev: undefined, + totalCount: 2, + error: null, + fetched: true, + fetching: false, + lastFetchedAt: now, + invalid: false, + }, true); + + const result = reducer(state, action); + const cache = result.TestEntity as EntityCache; + + expect([...cache.lists.thingies!.ids]).toEqual(['4', '5']); + expect(cache.lists.thingies!.state.lastFetchedAt).toBe(now); // Also check that newState worked +}); + test('deleting items', () => { const state: State = { TestEntity: { @@ -114,7 +153,7 @@ test('dismiss items', () => { TestEntity: { store: { '1': { id: '1' }, '2': { id: '2' }, '3': { id: '3' } }, lists: { - 'yolo': { + yolo: { ids: new Set(['1', '2', '3']), state: { ...createListState(), totalCount: 3 }, }, diff --git a/app/soapbox/entity-store/actions.ts b/app/soapbox/entity-store/actions.ts index 30ae75535c..8f4783c940 100644 --- a/app/soapbox/entity-store/actions.ts +++ b/app/soapbox/entity-store/actions.ts @@ -48,13 +48,20 @@ function entitiesFetchRequest(entityType: string, listKey?: string) { }; } -function entitiesFetchSuccess(entities: Entity[], entityType: string, listKey?: string, newState?: EntityListState) { +function entitiesFetchSuccess( + entities: Entity[], + entityType: string, + listKey?: string, + newState?: EntityListState, + overwrite = false, +) { return { type: ENTITIES_FETCH_SUCCESS, entityType, entities, listKey, newState, + overwrite, }; } diff --git a/app/soapbox/entity-store/hooks/useEntities.ts b/app/soapbox/entity-store/hooks/useEntities.ts index 9ba7ad4f39..996ee716f5 100644 --- a/app/soapbox/entity-store/hooks/useEntities.ts +++ b/app/soapbox/entity-store/hooks/useEntities.ts @@ -53,7 +53,7 @@ function useEntities( const next = useListState(path, 'next'); const prev = useListState(path, 'prev'); - const fetchPage = async(url: string): Promise => { + const fetchPage = async(url: string, overwrite = false): Promise => { // Get `isFetching` state from the store again to prevent race conditions. const isFetching = selectListState(getState(), path, 'fetching'); if (isFetching) return; @@ -74,7 +74,7 @@ function useEntities( error: null, lastFetchedAt: new Date(), invalid: false, - })); + }, overwrite)); } catch (error) { dispatch(entitiesFetchFail(entityType, listKey, error)); } @@ -82,7 +82,7 @@ function useEntities( const fetchEntities = async(): Promise => { if (endpoint) { - await fetchPage(endpoint); + await fetchPage(endpoint, true); } }; diff --git a/app/soapbox/entity-store/reducer.ts b/app/soapbox/entity-store/reducer.ts index 7654257cc0..082204e886 100644 --- a/app/soapbox/entity-store/reducer.ts +++ b/app/soapbox/entity-store/reducer.ts @@ -29,17 +29,25 @@ const importEntities = ( entities: Entity[], listKey?: string, newState?: EntityListState, + overwrite = false, ): State => { return produce(state, draft => { const cache = draft[entityType] ?? createCache(); cache.store = updateStore(cache.store, entities); if (typeof listKey === 'string') { - let list = { ...(cache.lists[listKey] ?? createList()) }; + let list = cache.lists[listKey] ?? createList(); + + if (overwrite) { + list.ids = new Set(); + } + list = updateList(list, entities); + if (newState) { list.state = newState; } + cache.lists[listKey] = list; } @@ -133,7 +141,7 @@ function reducer(state: Readonly = {}, action: EntityAction): State { case ENTITIES_DISMISS: return dismissEntities(state, action.entityType, action.ids, action.listKey); case ENTITIES_FETCH_SUCCESS: - return importEntities(state, action.entityType, action.entities, action.listKey, action.newState); + return importEntities(state, action.entityType, action.entities, action.listKey, action.newState, action.overwrite); case ENTITIES_FETCH_REQUEST: return setFetching(state, action.entityType, action.listKey, true); case ENTITIES_FETCH_FAIL: