Skip to content

Commit 9256449

Browse files
authored
fix: changed or deleted data get lost while still loading in useFind (#84)
* implement event cache
1 parent a904d5c commit 9256449

File tree

3 files changed

+67
-4
lines changed

3 files changed

+67
-4
lines changed

pnpm-lock.yaml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/useFind.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,16 @@ function loadServiceEventHandlers<
1414
service: FeathersService<CustomApplication, ServiceTypes<CustomApplication>[T]>,
1515
params: Ref<Params | undefined | null>,
1616
data: Ref<M[]>,
17+
isLoading: Ref<boolean>,
1718
): () => void {
19+
const eventCache: (() => void)[] = [];
20+
1821
const onCreated = (createdItem: M): void => {
22+
if (isLoading.value) {
23+
eventCache.push(() => onCreated(createdItem));
24+
return;
25+
}
26+
1927
// ignore items not matching the query or when no params are set
2028
if (!params.value || (params.value.query !== undefined && !sift(params.value.query)(createdItem))) {
2129
return;
@@ -30,10 +38,18 @@ function loadServiceEventHandlers<
3038
};
3139

3240
const onRemoved = (item: M): void => {
41+
if (isLoading.value) {
42+
eventCache.push(() => onRemoved(item));
43+
return;
44+
}
3345
data.value = data.value.filter((_item) => getId(_item) !== getId(item));
3446
};
3547

3648
const onItemChanged = (changedItem: M): void => {
49+
if (isLoading.value) {
50+
eventCache.push(() => onItemChanged(changedItem));
51+
return;
52+
}
3753
const existingItem = data.value.find((item) => getId(item) === getId(changedItem));
3854
const newItem = { ...existingItem, ...changedItem };
3955
// ignore items not matching the query or when no params are set
@@ -71,6 +87,15 @@ function loadServiceEventHandlers<
7187
service.off('updated', onItemChanged);
7288
};
7389

90+
watch(isLoading, () => {
91+
while (eventCache.length > 0 && !isLoading.value) {
92+
const event = eventCache.shift();
93+
if (event) {
94+
event();
95+
}
96+
}
97+
});
98+
7499
return unloadEventHandlers;
75100
}
76101

@@ -110,7 +135,7 @@ export default <CustomApplication extends Application>(feathers: CustomApplicati
110135
const error = ref<FeathersError>();
111136

112137
const service = feathers.service(serviceName as string);
113-
const unloadEventHandlers = loadServiceEventHandlers(service, params, data);
138+
const unloadEventHandlers = loadServiceEventHandlers(service, params, data, isLoading);
114139
let unloaded = false;
115140

116141
const currentFindCall = ref(0);

test/useFind.test.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ describe('Find composition', () => {
455455
});
456456

457457
describe('Event Handlers', () => {
458-
it('should listen to "create" events', () => {
458+
it('should listen to "create" events', async () => {
459459
expect.assertions(2);
460460

461461
// given
@@ -474,6 +474,7 @@ describe('Find composition', () => {
474474
mountComposition(() => {
475475
findComposition = useFind('testModels');
476476
});
477+
await nextTick();
477478

478479
// when
479480
emitter.emit('created', additionalTestModel);
@@ -541,7 +542,7 @@ describe('Find composition', () => {
541542
expect(findComposition && findComposition.data.value).toContainEqual(additionalTestModel);
542543
});
543544

544-
it('should ignore "create" events when query is not matching', () => {
545+
it('should ignore "create" events when query is not matching', async () => {
545546
expect.assertions(2);
546547

547548
// given
@@ -560,6 +561,7 @@ describe('Find composition', () => {
560561
mountComposition(() => {
561562
findComposition = useFind('testModels', ref({ query: { mood: 'please-do-not-match' } }));
562563
});
564+
await nextTick();
563565

564566
// when
565567
emitter.emit('created', additionalTestModel);
@@ -905,6 +907,40 @@ describe('Find composition', () => {
905907
expect(findComposition && findComposition.data.value).not.toContainEqual(testModel);
906908
});
907909

910+
it('should cache events when still loading', async () => {
911+
expect.assertions(4);
912+
913+
// given
914+
const emitter = eventHelper();
915+
const feathersMock = {
916+
service: () => ({
917+
find: vi.fn(() => [additionalTestModel2, testModel]),
918+
on: emitter.on,
919+
off: vi.fn(),
920+
}),
921+
on: vi.fn(),
922+
off: vi.fn(),
923+
} as unknown as Application;
924+
const useFind = useFindOriginal(feathersMock);
925+
let findComposition = null as UseFind<TestModel> | null;
926+
mountComposition(() => {
927+
findComposition = useFind('testModels');
928+
});
929+
930+
// when
931+
emitter.emit('updated', changedTestModel);
932+
emitter.emit('created', additionalTestModel);
933+
emitter.emit('removed', additionalTestModel2);
934+
await nextTick();
935+
await nextTick();
936+
937+
// then
938+
expect(findComposition).toBeTruthy();
939+
expect(findComposition && findComposition.data.value).toHaveLength(2);
940+
expect(findComposition && findComposition.data.value[0]).toStrictEqual(changedTestModel);
941+
expect(findComposition && findComposition.data.value[1]).toStrictEqual(additionalTestModel);
942+
});
943+
908944
it('should unload the event handlers', () => {
909945
expect.assertions(7);
910946

@@ -1073,6 +1109,7 @@ describe('Find composition', () => {
10731109
findComposition = useFind('testModels', undefined, { loadAllPages: true });
10741110
});
10751111
await nextTick();
1112+
await nextTick();
10761113

10771114
// then
10781115
expect(serviceFind).toHaveBeenCalledTimes(2);
@@ -1113,6 +1150,7 @@ describe('Find composition', () => {
11131150
findComposition = useFind('testModels', undefined, { loadAllPages: true });
11141151
});
11151152
await nextTick();
1153+
await nextTick();
11161154

11171155
// then
11181156
expect(serviceFind).toHaveBeenCalledTimes(2);

0 commit comments

Comments
 (0)