EntityStore: make fetching the first page override the old list

environments/review-group-requ-7youoa/deployments/2945
Alex Gleason 2 years ago
parent e2510489c5
commit cb8363d179
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7

@ -3,6 +3,7 @@ import {
dismissEntities, dismissEntities,
entitiesFetchFail, entitiesFetchFail,
entitiesFetchRequest, entitiesFetchRequest,
entitiesFetchSuccess,
importEntities, importEntities,
} from '../actions'; } from '../actions';
import reducer, { State } from '../reducer'; 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); 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<TestEntity>;
expect([...cache.lists.thingies!.ids]).toEqual(['4', '5']);
expect(cache.lists.thingies!.state.lastFetchedAt).toBe(now); // Also check that newState worked
});
test('deleting items', () => { test('deleting items', () => {
const state: State = { const state: State = {
TestEntity: { TestEntity: {
@ -114,7 +153,7 @@ test('dismiss items', () => {
TestEntity: { TestEntity: {
store: { '1': { id: '1' }, '2': { id: '2' }, '3': { id: '3' } }, store: { '1': { id: '1' }, '2': { id: '2' }, '3': { id: '3' } },
lists: { lists: {
'yolo': { yolo: {
ids: new Set(['1', '2', '3']), ids: new Set(['1', '2', '3']),
state: { ...createListState(), totalCount: 3 }, state: { ...createListState(), totalCount: 3 },
}, },

@ -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 { return {
type: ENTITIES_FETCH_SUCCESS, type: ENTITIES_FETCH_SUCCESS,
entityType, entityType,
entities, entities,
listKey, listKey,
newState, newState,
overwrite,
}; };
} }

@ -53,7 +53,7 @@ function useEntities<TEntity extends Entity>(
const next = useListState(path, 'next'); const next = useListState(path, 'next');
const prev = useListState(path, 'prev'); const prev = useListState(path, 'prev');
const fetchPage = async(url: string): Promise<void> => { const fetchPage = async(url: string, overwrite = false): Promise<void> => {
// Get `isFetching` state from the store again to prevent race conditions. // Get `isFetching` state from the store again to prevent race conditions.
const isFetching = selectListState(getState(), path, 'fetching'); const isFetching = selectListState(getState(), path, 'fetching');
if (isFetching) return; if (isFetching) return;
@ -74,7 +74,7 @@ function useEntities<TEntity extends Entity>(
error: null, error: null,
lastFetchedAt: new Date(), lastFetchedAt: new Date(),
invalid: false, invalid: false,
})); }, overwrite));
} catch (error) { } catch (error) {
dispatch(entitiesFetchFail(entityType, listKey, error)); dispatch(entitiesFetchFail(entityType, listKey, error));
} }
@ -82,7 +82,7 @@ function useEntities<TEntity extends Entity>(
const fetchEntities = async(): Promise<void> => { const fetchEntities = async(): Promise<void> => {
if (endpoint) { if (endpoint) {
await fetchPage(endpoint); await fetchPage(endpoint, true);
} }
}; };

@ -29,17 +29,25 @@ const importEntities = (
entities: Entity[], entities: Entity[],
listKey?: string, listKey?: string,
newState?: EntityListState, newState?: EntityListState,
overwrite = false,
): State => { ): State => {
return produce(state, draft => { return produce(state, draft => {
const cache = draft[entityType] ?? createCache(); const cache = draft[entityType] ?? createCache();
cache.store = updateStore(cache.store, entities); cache.store = updateStore(cache.store, entities);
if (typeof listKey === 'string') { 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); list = updateList(list, entities);
if (newState) { if (newState) {
list.state = newState; list.state = newState;
} }
cache.lists[listKey] = list; cache.lists[listKey] = list;
} }
@ -133,7 +141,7 @@ function reducer(state: Readonly<State> = {}, action: EntityAction): State {
case ENTITIES_DISMISS: case ENTITIES_DISMISS:
return dismissEntities(state, action.entityType, action.ids, action.listKey); return dismissEntities(state, action.entityType, action.ids, action.listKey);
case ENTITIES_FETCH_SUCCESS: 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: case ENTITIES_FETCH_REQUEST:
return setFetching(state, action.entityType, action.listKey, true); return setFetching(state, action.entityType, action.listKey, true);
case ENTITIES_FETCH_FAIL: case ENTITIES_FETCH_FAIL:

Loading…
Cancel
Save