@peerbit/react 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/useLocal.js +13 -7
- package/lib/esm/useLocal.js.map +1 -1
- package/lib/esm/usePeer.js +15 -4
- package/lib/esm/usePeer.js.map +1 -1
- package/lib/esm/{useLocalPaginated.d.ts → useQuery.d.ts} +10 -3
- package/lib/esm/useQuery.js +188 -0
- package/lib/esm/useQuery.js.map +1 -0
- package/package.json +3 -3
- package/src/index.ts +1 -1
- package/src/useLocal.tsx +32 -16
- package/src/usePeer.tsx +18 -4
- package/src/useQuery.tsx +306 -0
- package/lib/esm/useLocalPaginated.js +0 -135
- package/lib/esm/useLocalPaginated.js.map +0 -1
- package/src/useLocalPaginated.tsx +0 -208
package/lib/esm/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export * from "./utils.js";
|
|
|
3
3
|
export { FastMutex } from "./lockstorage.js";
|
|
4
4
|
export { useProgram } from "./useProgram.js";
|
|
5
5
|
export { useLocal } from "./useLocal.js";
|
|
6
|
-
export {
|
|
6
|
+
export { useQuery as useQuery } from "./useQuery.js";
|
|
7
7
|
export { useOnline } from "./useOnline.js";
|
|
8
8
|
export { useCount } from "./useCount.js";
|
|
9
9
|
export { debounceLeadingTrailing } from "./utils.js";
|
package/lib/esm/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export * from "./utils.js";
|
|
|
3
3
|
export { FastMutex } from "./lockstorage.js";
|
|
4
4
|
export { useProgram } from "./useProgram.js";
|
|
5
5
|
export { useLocal } from "./useLocal.js";
|
|
6
|
-
export {
|
|
6
|
+
export { useQuery as useQuery } from "./useQuery.js";
|
|
7
7
|
export { useOnline } from "./useOnline.js";
|
|
8
8
|
export { useCount } from "./useCount.js";
|
|
9
9
|
export { debounceLeadingTrailing } from "./utils.js";
|
package/lib/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,YAAY,EACZ,WAAW,EACX,OAAO,EACP,eAAe,GAClB,MAAM,cAAc,CAAC;AACtB,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,YAAY,EACZ,WAAW,EACX,OAAO,EACP,eAAe,GAClB,MAAM,cAAc,CAAC;AACtB,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC"}
|
package/lib/esm/useLocal.js
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { ClosedError } from "@peerbit/document";
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { debounceLeadingTrailing } from "./utils";
|
|
4
|
+
const logWithId = (options, ...args) => {
|
|
5
|
+
if (!options?.debug)
|
|
6
|
+
return;
|
|
7
|
+
if (typeof options.debug === "boolean") {
|
|
8
|
+
console.log(...args);
|
|
9
|
+
}
|
|
10
|
+
else if (typeof options.debug.id === "string") {
|
|
11
|
+
console.log(options.debug.id, ...args);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
4
14
|
export const useLocal = (db, options) => {
|
|
5
15
|
const [all, setAll] = useState([]);
|
|
6
16
|
const emptyResultsRef = useRef(false);
|
|
@@ -9,6 +19,7 @@ export const useLocal = (db, options) => {
|
|
|
9
19
|
// null query means no query at all
|
|
10
20
|
return;
|
|
11
21
|
}
|
|
22
|
+
logWithId(options, "reset local", db?.closed ? undefined : db?.rootAddress, options?.id, options?.resolve, options?.onChanges, options?.transform);
|
|
12
23
|
const _l = async (args) => {
|
|
13
24
|
try {
|
|
14
25
|
const iterator = db.index.iterate(options?.query ?? {}, {
|
|
@@ -20,12 +31,7 @@ export const useLocal = (db, options) => {
|
|
|
20
31
|
if (options?.transform) {
|
|
21
32
|
results = await Promise.all(results.map((x) => options.transform(x)));
|
|
22
33
|
}
|
|
23
|
-
|
|
24
|
-
let dbgId = typeof options.debug === "boolean"
|
|
25
|
-
? undefined
|
|
26
|
-
: options.debug.id;
|
|
27
|
-
console.log(dbgId ? "fetched " + dbgId : "fetched", results, "query", options?.query);
|
|
28
|
-
}
|
|
34
|
+
logWithId(options, options?.id, results, "query", options?.query);
|
|
29
35
|
emptyResultsRef.current = results.length === 0;
|
|
30
36
|
setAll(() => {
|
|
31
37
|
options?.onChanges?.(results);
|
|
@@ -39,7 +45,7 @@ export const useLocal = (db, options) => {
|
|
|
39
45
|
throw error;
|
|
40
46
|
}
|
|
41
47
|
};
|
|
42
|
-
const debounced = debounceLeadingTrailing(_l, options?.debounce ??
|
|
48
|
+
const debounced = debounceLeadingTrailing(_l, options?.debounce ?? 123);
|
|
43
49
|
const handleChange = () => {
|
|
44
50
|
if (emptyResultsRef.current) {
|
|
45
51
|
debounced.cancel();
|
package/lib/esm/useLocal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLocal.js","sourceRoot":"","sources":["../../src/useLocal.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA0B,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAWlD,MAAM,CAAC,MAAM,QAAQ,GAAG,CAMpB,EAAoB,EACpB,OAMe,EACjB,EAAE;IACA,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAO,EAAE,CAAC,CAAC;IACzC,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEtC,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,IAAI,OAAO,EAAE,KAAK,KAAK,IAAI,EAAE,CAAC;YAC9C,mCAAmC;YACnC,OAAO;QACX,CAAC;QAED,MAAM,EAAE,GAAG,KAAK,EAAE,IAAU,EAAE,EAAE;YAC5B,IAAI,CAAC;gBACD,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,EAAE;oBACpD,KAAK,EAAE,IAAI;oBACX,MAAM,EAAE,KAAK;oBACb,OAAO,EAAE,OAAO,EAAE,OAAc;iBACnC,CAAC,CAAC;gBAEH,IAAI,OAAO,GAAS,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAQ,CAAC;gBAElD,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC;oBACrB,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CACvB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAU,CAAC,CAAC,CAAC,CAAC,CAC5C,CAAC;gBACN,CAAC;gBACD,
|
|
1
|
+
{"version":3,"file":"useLocal.js","sourceRoot":"","sources":["../../src/useLocal.tsx"],"names":[],"mappings":"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"}
|
package/lib/esm/usePeer.js
CHANGED
|
@@ -15,6 +15,9 @@ import { webSockets } from "@libp2p/websockets";
|
|
|
15
15
|
import { circuitRelayTransport } from "@libp2p/circuit-relay-v2";
|
|
16
16
|
import * as filters from "@libp2p/websockets/filters";
|
|
17
17
|
import { detectIncognito } from "detectincognitojs";
|
|
18
|
+
const isInStandaloneMode = () => window.matchMedia("(display-mode: standalone)").matches ||
|
|
19
|
+
window.navigator["standalone"] ||
|
|
20
|
+
document.referrer.includes("android-app://");
|
|
18
21
|
export class ClientBusyError extends Error {
|
|
19
22
|
constructor(message) {
|
|
20
23
|
super(message);
|
|
@@ -26,6 +29,10 @@ if (!window.name) {
|
|
|
26
29
|
}
|
|
27
30
|
export const PeerContext = React.createContext({});
|
|
28
31
|
export const usePeer = () => useContext(PeerContext);
|
|
32
|
+
const subscribeToUnload = (fn) => {
|
|
33
|
+
window.addEventListener("pagehide", fn);
|
|
34
|
+
window.addEventListener("beforeunload", fn);
|
|
35
|
+
};
|
|
29
36
|
export const PeerProvider = (options) => {
|
|
30
37
|
const [peer, setPeer] = React.useState(undefined);
|
|
31
38
|
const [promise, setPromise] = React.useState(undefined);
|
|
@@ -96,9 +103,13 @@ export const PeerProvider = (options) => {
|
|
|
96
103
|
const localId = getClientId("local");
|
|
97
104
|
try {
|
|
98
105
|
const lockKey = localId + "-singleton";
|
|
99
|
-
|
|
106
|
+
subscribeToUnload(function () {
|
|
107
|
+
mutex.release(lockKey);
|
|
108
|
+
});
|
|
109
|
+
if (isInStandaloneMode()) {
|
|
110
|
+
// PWA issue fix (? TODO is this needed ?
|
|
100
111
|
mutex.release(lockKey);
|
|
101
|
-
}
|
|
112
|
+
}
|
|
102
113
|
await mutex.lock(lockKey, () => true, {
|
|
103
114
|
replaceIfSameClient: true,
|
|
104
115
|
});
|
|
@@ -117,9 +128,9 @@ export const PeerProvider = (options) => {
|
|
|
117
128
|
releaseFirstLock,
|
|
118
129
|
releaseLockIfSameId: true,
|
|
119
130
|
});
|
|
120
|
-
|
|
131
|
+
subscribeToUnload(function () {
|
|
121
132
|
mutex.release(kp.path);
|
|
122
|
-
};
|
|
133
|
+
});
|
|
123
134
|
nodeId = kp.key;
|
|
124
135
|
setTabIndex(kp.index);
|
|
125
136
|
}
|
package/lib/esm/usePeer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePeer.js","sourceRoot":"","sources":["../../src/usePeer.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"usePeer.js","sourceRoot":"","sources":["../../src/usePeer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Documents, WithContext } from "@peerbit/document";
|
|
1
|
+
import { Documents, DocumentsChange, WithContext } from "@peerbit/document";
|
|
2
2
|
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
3
3
|
type QueryLike = {
|
|
4
4
|
query?: indexerTypes.Query[] | indexerTypes.QueryLike;
|
|
@@ -8,16 +8,23 @@ type QueryOptions = {
|
|
|
8
8
|
query: QueryLike;
|
|
9
9
|
id: string;
|
|
10
10
|
};
|
|
11
|
-
export declare const
|
|
11
|
+
export declare const useQuery: <T extends Record<string, any>, I extends Record<string, any>, R extends boolean | undefined = true, RT = R extends false ? WithContext<I> : WithContext<T>>(db?: Documents<T, I>, options?: {
|
|
12
12
|
resolve?: R;
|
|
13
13
|
transform?: (result: WithContext<RT>) => Promise<WithContext<RT>>;
|
|
14
|
-
onChanges?: (all: RT[]) => void;
|
|
15
14
|
debounce?: number;
|
|
16
15
|
debug?: boolean | {
|
|
17
16
|
id: string;
|
|
18
17
|
};
|
|
19
18
|
reverse?: boolean;
|
|
20
19
|
batchSize?: number;
|
|
20
|
+
onChange?: {
|
|
21
|
+
merge?: boolean | ((change: DocumentsChange<T>) => DocumentsChange<T> | Promise<DocumentsChange<T>> | undefined);
|
|
22
|
+
update?: (prev: WithContext<RT>[], change: DocumentsChange<T>) => WithContext<RT>[];
|
|
23
|
+
};
|
|
24
|
+
local?: boolean;
|
|
25
|
+
remote?: boolean | {
|
|
26
|
+
eager?: boolean;
|
|
27
|
+
};
|
|
21
28
|
} & QueryOptions) => {
|
|
22
29
|
items: WithContext<RT>[];
|
|
23
30
|
loadMore: () => Promise<void>;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from "react";
|
|
2
|
+
import { ClosedError, } from "@peerbit/document";
|
|
3
|
+
const logWithId = (options, ...args) => {
|
|
4
|
+
if (!options?.debug)
|
|
5
|
+
return;
|
|
6
|
+
if (typeof options.debug === "boolean") {
|
|
7
|
+
console.log(...args);
|
|
8
|
+
}
|
|
9
|
+
else if (typeof options.debug.id === "string") {
|
|
10
|
+
console.log(options.debug.id, ...args);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export const useQuery = (db, options) => {
|
|
14
|
+
const [all, setAll] = useState([]);
|
|
15
|
+
const allRef = useRef([]);
|
|
16
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
17
|
+
const loadingMoreRef = useRef(false);
|
|
18
|
+
const iteratorRef = useRef(null);
|
|
19
|
+
const emptyResultsRef = useRef(false);
|
|
20
|
+
const updateAll = (combined, fromChange) => {
|
|
21
|
+
logWithId(options, "Loading more items, new combined length", combined.length, "from change", fromChange);
|
|
22
|
+
allRef.current = combined;
|
|
23
|
+
setAll(combined);
|
|
24
|
+
};
|
|
25
|
+
const reset = () => {
|
|
26
|
+
logWithId(options, "RESET FROM " + allRef.current.length);
|
|
27
|
+
emptyResultsRef.current = false;
|
|
28
|
+
!iteratorRef.current?.iterator.done() &&
|
|
29
|
+
iteratorRef.current?.iterator?.close();
|
|
30
|
+
iteratorRef.current = null;
|
|
31
|
+
setAll([]);
|
|
32
|
+
setIsLoading(false);
|
|
33
|
+
loadingMoreRef.current = false;
|
|
34
|
+
allRef.current = [];
|
|
35
|
+
};
|
|
36
|
+
// Initialize the iterator only once or when query changes
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!db || db.closed || options?.query === null) {
|
|
39
|
+
reset();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const initIterator = () => {
|
|
43
|
+
// Don't make this async, it will cause issues with the iterator refs
|
|
44
|
+
try {
|
|
45
|
+
// Initialize the iterator and load initial batch.
|
|
46
|
+
emptyResultsRef.current = false;
|
|
47
|
+
iteratorRef.current?.iterator.close();
|
|
48
|
+
iteratorRef.current = {
|
|
49
|
+
id: options?.id,
|
|
50
|
+
iterator: db.index.iterate(options?.query ?? {}, {
|
|
51
|
+
local: options?.local ?? true,
|
|
52
|
+
remote: options?.remote ?? true,
|
|
53
|
+
resolve: options?.resolve,
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
logWithId(options, "Initializing iterator", options?.id);
|
|
57
|
+
loadMore(); // initial load
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.error("Error initializing iterator", error);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
// Reset state when the db or query changes.
|
|
64
|
+
reset();
|
|
65
|
+
initIterator();
|
|
66
|
+
let handleChange = undefined;
|
|
67
|
+
if (options?.onChange) {
|
|
68
|
+
let mergeFunction = typeof options.onChange.merge === "function"
|
|
69
|
+
? options.onChange.merge
|
|
70
|
+
: (change) => change;
|
|
71
|
+
handleChange = async (e) => {
|
|
72
|
+
// while we are iterating, we might get new documents.. so this method inserts them where they should be
|
|
73
|
+
let filteredChange = await mergeFunction(e.detail);
|
|
74
|
+
if (!filteredChange ||
|
|
75
|
+
(filteredChange.added.length === 0 &&
|
|
76
|
+
filteredChange.removed.length === 0)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
let merged = [];
|
|
80
|
+
if (options.onChange?.update) {
|
|
81
|
+
merged = [
|
|
82
|
+
...options.onChange.update(allRef.current, filteredChange),
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
merged = await db.index.updateResults(allRef.current, filteredChange, options?.query || {}, options?.resolve ?? true);
|
|
87
|
+
const expectedDiff = filteredChange.added.length -
|
|
88
|
+
filteredChange.removed.length;
|
|
89
|
+
if (merged === allRef.current ||
|
|
90
|
+
(expectedDiff !== 0 &&
|
|
91
|
+
merged.length === allRef.current.length)) {
|
|
92
|
+
// no change
|
|
93
|
+
logWithId(options, "no change after merge");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
logWithId(options, "handleChange", {
|
|
98
|
+
added: e.detail.added.length,
|
|
99
|
+
removed: e.detail.removed.length,
|
|
100
|
+
merged: merged.length,
|
|
101
|
+
allRef: allRef.current.length,
|
|
102
|
+
});
|
|
103
|
+
updateAll(options?.reverse ? merged.reverse() : merged, e.detail);
|
|
104
|
+
};
|
|
105
|
+
db.events.addEventListener("change", handleChange);
|
|
106
|
+
}
|
|
107
|
+
return () => {
|
|
108
|
+
handleChange &&
|
|
109
|
+
db.events.removeEventListener("change", handleChange);
|
|
110
|
+
reset();
|
|
111
|
+
};
|
|
112
|
+
}, [
|
|
113
|
+
db?.closed ? undefined : db?.address,
|
|
114
|
+
options?.id ? options?.id : options?.query,
|
|
115
|
+
options?.resolve,
|
|
116
|
+
]);
|
|
117
|
+
// Define the loadMore function
|
|
118
|
+
const batchSize = options?.batchSize ?? 10;
|
|
119
|
+
const loadMore = async () => {
|
|
120
|
+
if (!iteratorRef.current ||
|
|
121
|
+
emptyResultsRef.current ||
|
|
122
|
+
iteratorRef.current.iterator.done() ||
|
|
123
|
+
loadingMoreRef.current) {
|
|
124
|
+
logWithId(options, "loadMore: already loading or no more items", {
|
|
125
|
+
isLoading,
|
|
126
|
+
emptyResultsRef: emptyResultsRef.current,
|
|
127
|
+
iteratorRef: !iteratorRef.current,
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const iterator = iteratorRef.current;
|
|
132
|
+
setIsLoading(true);
|
|
133
|
+
loadingMoreRef.current = true;
|
|
134
|
+
try {
|
|
135
|
+
// Fetch next batchSize number of items:
|
|
136
|
+
await db?.log.waitForReplicators({ timeout: 1e4 });
|
|
137
|
+
logWithId(options, "loadMore: loading more items for iterator" +
|
|
138
|
+
iteratorRef.current?.id);
|
|
139
|
+
let newItems = await iterator.iterator.next(batchSize);
|
|
140
|
+
if (options?.transform) {
|
|
141
|
+
newItems = await Promise.all(newItems.map((item) => options.transform(item)));
|
|
142
|
+
}
|
|
143
|
+
if (iteratorRef.current !== iterator) {
|
|
144
|
+
// If the iterator has changed, we should not update the state
|
|
145
|
+
// This can happen if the iterator was closed and a new one was created
|
|
146
|
+
logWithId(options, "Iterator ref changed, not updating state", {
|
|
147
|
+
refBefore: iterator.id,
|
|
148
|
+
currentRef: iteratorRef.current?.id,
|
|
149
|
+
});
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
emptyResultsRef.current = newItems.length === 0;
|
|
153
|
+
if (newItems.length > 0) {
|
|
154
|
+
let prev = allRef.current;
|
|
155
|
+
let prevHash = new Set(prev.map((x) => x.__context.head));
|
|
156
|
+
let newItemsNoHash = newItems.filter((x) => !prevHash.has(x.__context.head));
|
|
157
|
+
if (newItemsNoHash.length === 0) {
|
|
158
|
+
logWithId(options, "no new items after dedup, not updating state. Prev length", prev.length);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const combined = options?.reverse
|
|
162
|
+
? [...newItemsNoHash.reverse(), ...prev]
|
|
163
|
+
: [...prev, ...newItemsNoHash];
|
|
164
|
+
updateAll(combined, null);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
logWithId(options, "no new items, not updating state for iterator" +
|
|
168
|
+
iteratorRef.current?.id +
|
|
169
|
+
" existing results length", allRef.current.length);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
if (error instanceof ClosedError) {
|
|
174
|
+
// Handle closed database gracefully
|
|
175
|
+
logWithId(options, "Database closed error");
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
setIsLoading(false);
|
|
183
|
+
loadingMoreRef.current = false;
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
return { items: all, loadMore, isLoading, empty: emptyResultsRef.current };
|
|
187
|
+
};
|
|
188
|
+
//# sourceMappingURL=useQuery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useQuery.js","sourceRoot":"","sources":["../../src/useQuery.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peerbit/react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"homepage": "https://dao-xyz.github.io/peerbit-examples",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"peerbit": "^4",
|
|
35
35
|
"react": "^18.2.0",
|
|
36
36
|
"react-dom": "^18.2.0",
|
|
37
|
-
"react-router
|
|
37
|
+
"react-router": "^7.5.0",
|
|
38
38
|
"react-use": "^17.4.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"last 1 safari version"
|
|
71
71
|
]
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "b5151c6b800226ed660cdec491fbf6f05a021c2f"
|
|
74
74
|
}
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ export * from "./utils.js";
|
|
|
8
8
|
export { FastMutex } from "./lockstorage.js";
|
|
9
9
|
export { useProgram } from "./useProgram.js";
|
|
10
10
|
export { useLocal } from "./useLocal.js";
|
|
11
|
-
export {
|
|
11
|
+
export { useQuery as useQuery } from "./useQuery.js";
|
|
12
12
|
export { useOnline } from "./useOnline.js";
|
|
13
13
|
export { useCount } from "./useCount.js";
|
|
14
14
|
export { debounceLeadingTrailing } from "./utils.js";
|
package/src/useLocal.tsx
CHANGED
|
@@ -12,6 +12,19 @@ type QueryOptons = {
|
|
|
12
12
|
id: string;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
const logWithId = (
|
|
16
|
+
options: { debug?: boolean | { id: string } } | undefined,
|
|
17
|
+
...args: any[]
|
|
18
|
+
) => {
|
|
19
|
+
if (!options?.debug) return;
|
|
20
|
+
|
|
21
|
+
if (typeof options.debug === "boolean") {
|
|
22
|
+
console.log(...args);
|
|
23
|
+
} else if (typeof options.debug.id === "string") {
|
|
24
|
+
console.log(options.debug.id, ...args);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
15
28
|
export const useLocal = <
|
|
16
29
|
T extends Record<string, any>,
|
|
17
30
|
I extends Record<string, any>,
|
|
@@ -36,6 +49,16 @@ export const useLocal = <
|
|
|
36
49
|
return;
|
|
37
50
|
}
|
|
38
51
|
|
|
52
|
+
logWithId(
|
|
53
|
+
options,
|
|
54
|
+
"reset local",
|
|
55
|
+
db?.closed ? undefined : db?.rootAddress,
|
|
56
|
+
options?.id,
|
|
57
|
+
options?.resolve,
|
|
58
|
+
options?.onChanges,
|
|
59
|
+
options?.transform
|
|
60
|
+
);
|
|
61
|
+
|
|
39
62
|
const _l = async (args?: any) => {
|
|
40
63
|
try {
|
|
41
64
|
const iterator = db.index.iterate(options?.query ?? {}, {
|
|
@@ -51,18 +74,14 @@ export const useLocal = <
|
|
|
51
74
|
results.map((x) => options.transform!(x))
|
|
52
75
|
);
|
|
53
76
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"query",
|
|
63
|
-
options?.query
|
|
64
|
-
);
|
|
65
|
-
}
|
|
77
|
+
logWithId(
|
|
78
|
+
options,
|
|
79
|
+
options?.id,
|
|
80
|
+
results,
|
|
81
|
+
"query",
|
|
82
|
+
options?.query
|
|
83
|
+
);
|
|
84
|
+
|
|
66
85
|
emptyResultsRef.current = results.length === 0;
|
|
67
86
|
setAll(() => {
|
|
68
87
|
options?.onChanges?.(results);
|
|
@@ -76,10 +95,7 @@ export const useLocal = <
|
|
|
76
95
|
}
|
|
77
96
|
};
|
|
78
97
|
|
|
79
|
-
const debounced = debounceLeadingTrailing(
|
|
80
|
-
_l,
|
|
81
|
-
options?.debounce ?? 1000
|
|
82
|
-
);
|
|
98
|
+
const debounced = debounceLeadingTrailing(_l, options?.debounce ?? 123);
|
|
83
99
|
|
|
84
100
|
const handleChange = () => {
|
|
85
101
|
if (emptyResultsRef.current) {
|
package/src/usePeer.tsx
CHANGED
|
@@ -24,6 +24,11 @@ import { circuitRelayTransport } from "@libp2p/circuit-relay-v2";
|
|
|
24
24
|
import * as filters from "@libp2p/websockets/filters";
|
|
25
25
|
import { detectIncognito } from "detectincognitojs";
|
|
26
26
|
|
|
27
|
+
const isInStandaloneMode = () =>
|
|
28
|
+
window.matchMedia("(display-mode: standalone)").matches ||
|
|
29
|
+
window.navigator["standalone"] ||
|
|
30
|
+
document.referrer.includes("android-app://");
|
|
31
|
+
|
|
27
32
|
export class ClientBusyError extends Error {
|
|
28
33
|
constructor(message: string) {
|
|
29
34
|
super(message);
|
|
@@ -95,6 +100,11 @@ type WithChildren = {
|
|
|
95
100
|
};
|
|
96
101
|
type PeerOptions = (TopAndIframeOptions | TopOptions) & WithChildren;
|
|
97
102
|
|
|
103
|
+
const subscribeToUnload = (fn: () => any) => {
|
|
104
|
+
window.addEventListener("pagehide", fn);
|
|
105
|
+
window.addEventListener("beforeunload", fn);
|
|
106
|
+
};
|
|
107
|
+
|
|
98
108
|
export const PeerProvider = (options: PeerOptions) => {
|
|
99
109
|
const [peer, setPeer] = React.useState<ProgramClient | undefined>(
|
|
100
110
|
undefined
|
|
@@ -182,9 +192,13 @@ export const PeerProvider = (options: PeerOptions) => {
|
|
|
182
192
|
const localId = getClientId("local");
|
|
183
193
|
try {
|
|
184
194
|
const lockKey = localId + "-singleton";
|
|
185
|
-
|
|
195
|
+
subscribeToUnload(function () {
|
|
186
196
|
mutex.release(lockKey);
|
|
187
|
-
};
|
|
197
|
+
});
|
|
198
|
+
if (isInStandaloneMode()) {
|
|
199
|
+
// PWA issue fix (? TODO is this needed ?
|
|
200
|
+
mutex.release(lockKey);
|
|
201
|
+
}
|
|
188
202
|
await mutex.lock(lockKey, () => true, {
|
|
189
203
|
replaceIfSameClient: true,
|
|
190
204
|
});
|
|
@@ -204,9 +218,9 @@ export const PeerProvider = (options: PeerOptions) => {
|
|
|
204
218
|
releaseFirstLock,
|
|
205
219
|
releaseLockIfSameId: true,
|
|
206
220
|
});
|
|
207
|
-
|
|
221
|
+
subscribeToUnload(function () {
|
|
208
222
|
mutex.release(kp.path);
|
|
209
|
-
};
|
|
223
|
+
});
|
|
210
224
|
nodeId = kp.key;
|
|
211
225
|
setTabIndex(kp.index);
|
|
212
226
|
}
|
package/src/useQuery.tsx
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
ClosedError,
|
|
4
|
+
Documents,
|
|
5
|
+
DocumentsChange,
|
|
6
|
+
ResultsIterator,
|
|
7
|
+
WithContext,
|
|
8
|
+
} from "@peerbit/document";
|
|
9
|
+
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
10
|
+
|
|
11
|
+
type QueryLike = {
|
|
12
|
+
query?: indexerTypes.Query[] | indexerTypes.QueryLike;
|
|
13
|
+
sort?: indexerTypes.Sort[] | indexerTypes.Sort | indexerTypes.SortLike;
|
|
14
|
+
};
|
|
15
|
+
type QueryOptions = { query: QueryLike; id: string };
|
|
16
|
+
|
|
17
|
+
const logWithId = (
|
|
18
|
+
options: { debug?: boolean | { id: string } } | undefined,
|
|
19
|
+
...args: any[]
|
|
20
|
+
) => {
|
|
21
|
+
if (!options?.debug) return;
|
|
22
|
+
|
|
23
|
+
if (typeof options.debug === "boolean") {
|
|
24
|
+
console.log(...args);
|
|
25
|
+
} else if (typeof options.debug.id === "string") {
|
|
26
|
+
console.log(options.debug.id, ...args);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const useQuery = <
|
|
31
|
+
T extends Record<string, any>,
|
|
32
|
+
I extends Record<string, any>,
|
|
33
|
+
R extends boolean | undefined = true,
|
|
34
|
+
RT = R extends false ? WithContext<I> : WithContext<T>
|
|
35
|
+
>(
|
|
36
|
+
db?: Documents<T, I>,
|
|
37
|
+
options?: {
|
|
38
|
+
resolve?: R;
|
|
39
|
+
transform?: (result: WithContext<RT>) => Promise<WithContext<RT>>;
|
|
40
|
+
debounce?: number;
|
|
41
|
+
debug?: boolean | { id: string };
|
|
42
|
+
reverse?: boolean;
|
|
43
|
+
batchSize?: number; // You can set a default batch size here
|
|
44
|
+
onChange?: {
|
|
45
|
+
merge?:
|
|
46
|
+
| boolean
|
|
47
|
+
| ((
|
|
48
|
+
change: DocumentsChange<T>
|
|
49
|
+
) =>
|
|
50
|
+
| DocumentsChange<T>
|
|
51
|
+
| Promise<DocumentsChange<T>>
|
|
52
|
+
| undefined); // if true, the iterator will be updated with new documents
|
|
53
|
+
update?: (
|
|
54
|
+
prev: WithContext<RT>[],
|
|
55
|
+
change: DocumentsChange<T>
|
|
56
|
+
) => WithContext<RT>[];
|
|
57
|
+
};
|
|
58
|
+
local?: boolean; // if true, (default is true) the iterator will only return local documents
|
|
59
|
+
remote?:
|
|
60
|
+
| boolean
|
|
61
|
+
| {
|
|
62
|
+
eager?: boolean;
|
|
63
|
+
};
|
|
64
|
+
} & QueryOptions
|
|
65
|
+
) => {
|
|
66
|
+
const [all, setAll] = useState<WithContext<RT>[]>([]);
|
|
67
|
+
const allRef = useRef<WithContext<RT>[]>([]);
|
|
68
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
69
|
+
const loadingMoreRef = useRef(false);
|
|
70
|
+
const iteratorRef = useRef<{
|
|
71
|
+
id?: string;
|
|
72
|
+
iterator: ResultsIterator<WithContext<RT>>;
|
|
73
|
+
} | null>(null);
|
|
74
|
+
const emptyResultsRef = useRef(false);
|
|
75
|
+
|
|
76
|
+
const updateAll = (
|
|
77
|
+
combined: WithContext<RT>[],
|
|
78
|
+
fromChange?: DocumentsChange<any> | null
|
|
79
|
+
) => {
|
|
80
|
+
logWithId(
|
|
81
|
+
options,
|
|
82
|
+
"Loading more items, new combined length",
|
|
83
|
+
combined.length,
|
|
84
|
+
"from change",
|
|
85
|
+
fromChange
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
allRef.current = combined;
|
|
89
|
+
|
|
90
|
+
setAll(combined);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const reset = () => {
|
|
94
|
+
logWithId(options, "RESET FROM " + allRef.current.length);
|
|
95
|
+
|
|
96
|
+
emptyResultsRef.current = false;
|
|
97
|
+
!iteratorRef.current?.iterator.done() &&
|
|
98
|
+
iteratorRef.current?.iterator?.close();
|
|
99
|
+
iteratorRef.current = null;
|
|
100
|
+
setAll([]);
|
|
101
|
+
setIsLoading(false);
|
|
102
|
+
loadingMoreRef.current = false;
|
|
103
|
+
allRef.current = [];
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Initialize the iterator only once or when query changes
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (!db || db.closed || options?.query === null) {
|
|
109
|
+
reset();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const initIterator = () => {
|
|
113
|
+
// Don't make this async, it will cause issues with the iterator refs
|
|
114
|
+
try {
|
|
115
|
+
// Initialize the iterator and load initial batch.
|
|
116
|
+
|
|
117
|
+
emptyResultsRef.current = false;
|
|
118
|
+
iteratorRef.current?.iterator.close();
|
|
119
|
+
iteratorRef.current = {
|
|
120
|
+
id: options?.id,
|
|
121
|
+
iterator: db.index.iterate(options?.query ?? {}, {
|
|
122
|
+
local: options?.local ?? true,
|
|
123
|
+
remote: options?.remote ?? true,
|
|
124
|
+
resolve: options?.resolve as any,
|
|
125
|
+
}) as any as ResultsIterator<WithContext<RT>>,
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
logWithId(options, "Initializing iterator", options?.id);
|
|
129
|
+
|
|
130
|
+
loadMore(); // initial load
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error("Error initializing iterator", error);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Reset state when the db or query changes.
|
|
137
|
+
reset();
|
|
138
|
+
initIterator();
|
|
139
|
+
|
|
140
|
+
let handleChange:
|
|
141
|
+
| undefined
|
|
142
|
+
| ((e: CustomEvent<DocumentsChange<T>>) => void | Promise<void>) =
|
|
143
|
+
undefined;
|
|
144
|
+
if (options?.onChange) {
|
|
145
|
+
let mergeFunction =
|
|
146
|
+
typeof options.onChange.merge === "function"
|
|
147
|
+
? options.onChange.merge
|
|
148
|
+
: (change: DocumentsChange<T>) => change;
|
|
149
|
+
handleChange = async (e: CustomEvent<DocumentsChange<T>>) => {
|
|
150
|
+
// while we are iterating, we might get new documents.. so this method inserts them where they should be
|
|
151
|
+
let filteredChange = await mergeFunction(e.detail);
|
|
152
|
+
if (
|
|
153
|
+
!filteredChange ||
|
|
154
|
+
(filteredChange.added.length === 0 &&
|
|
155
|
+
filteredChange.removed.length === 0)
|
|
156
|
+
) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
let merged: WithContext<RT>[] = [];
|
|
160
|
+
if (options.onChange?.update) {
|
|
161
|
+
merged = [
|
|
162
|
+
...options.onChange.update(
|
|
163
|
+
allRef.current,
|
|
164
|
+
filteredChange
|
|
165
|
+
),
|
|
166
|
+
];
|
|
167
|
+
} else {
|
|
168
|
+
merged = await db.index.updateResults(
|
|
169
|
+
allRef.current,
|
|
170
|
+
filteredChange,
|
|
171
|
+
options?.query || {},
|
|
172
|
+
options?.resolve ?? true
|
|
173
|
+
);
|
|
174
|
+
const expectedDiff =
|
|
175
|
+
filteredChange.added.length -
|
|
176
|
+
filteredChange.removed.length;
|
|
177
|
+
|
|
178
|
+
if (
|
|
179
|
+
merged === allRef.current ||
|
|
180
|
+
(expectedDiff !== 0 &&
|
|
181
|
+
merged.length === allRef.current.length)
|
|
182
|
+
) {
|
|
183
|
+
// no change
|
|
184
|
+
logWithId(options, "no change after merge");
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
logWithId(options, "handleChange", {
|
|
190
|
+
added: e.detail.added.length,
|
|
191
|
+
removed: e.detail.removed.length,
|
|
192
|
+
merged: merged.length,
|
|
193
|
+
allRef: allRef.current.length,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
updateAll(
|
|
197
|
+
options?.reverse ? merged.reverse() : merged,
|
|
198
|
+
e.detail
|
|
199
|
+
);
|
|
200
|
+
};
|
|
201
|
+
db.events.addEventListener("change", handleChange);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return () => {
|
|
205
|
+
handleChange &&
|
|
206
|
+
db.events.removeEventListener("change", handleChange);
|
|
207
|
+
reset();
|
|
208
|
+
};
|
|
209
|
+
}, [
|
|
210
|
+
db?.closed ? undefined : db?.address,
|
|
211
|
+
options?.id ? options?.id : options?.query,
|
|
212
|
+
options?.resolve,
|
|
213
|
+
]);
|
|
214
|
+
|
|
215
|
+
// Define the loadMore function
|
|
216
|
+
const batchSize = options?.batchSize ?? 10;
|
|
217
|
+
const loadMore = async () => {
|
|
218
|
+
if (
|
|
219
|
+
!iteratorRef.current ||
|
|
220
|
+
emptyResultsRef.current ||
|
|
221
|
+
iteratorRef.current.iterator.done() ||
|
|
222
|
+
loadingMoreRef.current
|
|
223
|
+
) {
|
|
224
|
+
logWithId(options, "loadMore: already loading or no more items", {
|
|
225
|
+
isLoading,
|
|
226
|
+
emptyResultsRef: emptyResultsRef.current,
|
|
227
|
+
iteratorRef: !iteratorRef.current,
|
|
228
|
+
});
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const iterator = iteratorRef.current;
|
|
232
|
+
|
|
233
|
+
setIsLoading(true);
|
|
234
|
+
loadingMoreRef.current = true;
|
|
235
|
+
try {
|
|
236
|
+
// Fetch next batchSize number of items:
|
|
237
|
+
await db?.log.waitForReplicators({ timeout: 1e4 });
|
|
238
|
+
logWithId(
|
|
239
|
+
options,
|
|
240
|
+
"loadMore: loading more items for iterator" +
|
|
241
|
+
iteratorRef.current?.id
|
|
242
|
+
);
|
|
243
|
+
let newItems: WithContext<RT>[] = await iterator.iterator.next(
|
|
244
|
+
batchSize
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
if (options?.transform) {
|
|
248
|
+
newItems = await Promise.all(
|
|
249
|
+
newItems.map((item) => options.transform!(item))
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (iteratorRef.current !== iterator) {
|
|
254
|
+
// If the iterator has changed, we should not update the state
|
|
255
|
+
// This can happen if the iterator was closed and a new one was created
|
|
256
|
+
logWithId(options, "Iterator ref changed, not updating state", {
|
|
257
|
+
refBefore: iterator.id,
|
|
258
|
+
currentRef: iteratorRef.current?.id,
|
|
259
|
+
});
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
emptyResultsRef.current = newItems.length === 0;
|
|
264
|
+
|
|
265
|
+
if (newItems.length > 0) {
|
|
266
|
+
let prev = allRef.current;
|
|
267
|
+
let prevHash = new Set(prev.map((x) => x.__context.head));
|
|
268
|
+
let newItemsNoHash = newItems.filter(
|
|
269
|
+
(x) => !prevHash.has(x.__context.head)
|
|
270
|
+
);
|
|
271
|
+
if (newItemsNoHash.length === 0) {
|
|
272
|
+
logWithId(
|
|
273
|
+
options,
|
|
274
|
+
"no new items after dedup, not updating state. Prev length",
|
|
275
|
+
prev.length
|
|
276
|
+
);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const combined = options?.reverse
|
|
280
|
+
? [...newItemsNoHash.reverse(), ...prev]
|
|
281
|
+
: [...prev, ...newItemsNoHash];
|
|
282
|
+
updateAll(combined, null);
|
|
283
|
+
} else {
|
|
284
|
+
logWithId(
|
|
285
|
+
options,
|
|
286
|
+
"no new items, not updating state for iterator" +
|
|
287
|
+
iteratorRef.current?.id +
|
|
288
|
+
" existing results length",
|
|
289
|
+
allRef.current.length
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
} catch (error) {
|
|
293
|
+
if (error instanceof ClosedError) {
|
|
294
|
+
// Handle closed database gracefully
|
|
295
|
+
logWithId(options, "Database closed error");
|
|
296
|
+
} else {
|
|
297
|
+
throw error;
|
|
298
|
+
}
|
|
299
|
+
} finally {
|
|
300
|
+
setIsLoading(false);
|
|
301
|
+
loadingMoreRef.current = false;
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
return { items: all, loadMore, isLoading, empty: emptyResultsRef.current };
|
|
306
|
+
};
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useRef } from "react";
|
|
2
|
-
import { ClosedError, } from "@peerbit/document";
|
|
3
|
-
export const useLocalPaginated = (db, options) => {
|
|
4
|
-
const [all, setAll] = useState([]);
|
|
5
|
-
const allRef = useRef([]);
|
|
6
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
7
|
-
const iteratorRef = useRef(null);
|
|
8
|
-
const emptyResultsRef = useRef(false);
|
|
9
|
-
const updateAll = (combined) => {
|
|
10
|
-
if (options?.onChanges) {
|
|
11
|
-
options?.onChanges?.(combined);
|
|
12
|
-
}
|
|
13
|
-
if (options?.debug) {
|
|
14
|
-
let dbgId = typeof options.debug === "boolean"
|
|
15
|
-
? undefined
|
|
16
|
-
: options.debug.id;
|
|
17
|
-
console.log("Loading more items, new combined length", dbgId, combined.length);
|
|
18
|
-
}
|
|
19
|
-
const dedub = new Set();
|
|
20
|
-
for (const item of combined) {
|
|
21
|
-
if ("idString" in item) {
|
|
22
|
-
if (dedub.has(item.idString)) {
|
|
23
|
-
throw new Error("Duplicate item found in iterator");
|
|
24
|
-
}
|
|
25
|
-
dedub.add(item.idString);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
allRef.current = combined;
|
|
29
|
-
setAll(combined);
|
|
30
|
-
};
|
|
31
|
-
// Initialize the iterator only once or when query changes
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (!db || db.closed || options?.query === null) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
const initIterator = () => {
|
|
37
|
-
try {
|
|
38
|
-
// Initialize the iterator and load initial batch.
|
|
39
|
-
emptyResultsRef.current = false;
|
|
40
|
-
iteratorRef.current?.close();
|
|
41
|
-
iteratorRef.current = db.index.iterate(options?.query ?? {}, {
|
|
42
|
-
local: true,
|
|
43
|
-
remote: false,
|
|
44
|
-
resolve: options?.resolve,
|
|
45
|
-
}); // TODO types
|
|
46
|
-
if (options?.debug) {
|
|
47
|
-
let dbgId = typeof options.debug === "boolean"
|
|
48
|
-
? undefined
|
|
49
|
-
: options.debug.id;
|
|
50
|
-
console.log("Create new iterator", dbgId);
|
|
51
|
-
}
|
|
52
|
-
loadMore(); // initial load
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
console.error("Error initializing iterator", error);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
// Reset state when the db or query changes.
|
|
59
|
-
console.log("RESET FROM", all.length);
|
|
60
|
-
setAll([]);
|
|
61
|
-
allRef.current = [];
|
|
62
|
-
initIterator();
|
|
63
|
-
const handleChange = async (e) => {
|
|
64
|
-
// while we are iterating, we might get new documents.. so this method inserts them where they should be
|
|
65
|
-
let merged = await db.index.updateResults(allRef.current, e.detail, options?.query || {}, options?.resolve ?? true);
|
|
66
|
-
console.log("merge result", "change: " +
|
|
67
|
-
(merged === allRef.current &&
|
|
68
|
-
merged.length &&
|
|
69
|
-
allRef.current.length === 0), merged, all, e.detail, allRef.current);
|
|
70
|
-
if (merged === allRef.current &&
|
|
71
|
-
merged.length &&
|
|
72
|
-
allRef.current.length === 0) {
|
|
73
|
-
// no change
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
updateAll(options?.reverse ? merged.reverse() : merged);
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
db.events.addEventListener("change", handleChange);
|
|
80
|
-
return () => {
|
|
81
|
-
db.events.removeEventListener("change", handleChange);
|
|
82
|
-
iteratorRef.current?.close();
|
|
83
|
-
};
|
|
84
|
-
}, [
|
|
85
|
-
db?.closed ? undefined : db?.rootAddress,
|
|
86
|
-
options?.id,
|
|
87
|
-
options?.query,
|
|
88
|
-
options?.resolve,
|
|
89
|
-
]);
|
|
90
|
-
// Define the loadMore function
|
|
91
|
-
const loadMore = async () => {
|
|
92
|
-
if (!iteratorRef.current || isLoading || emptyResultsRef.current)
|
|
93
|
-
return;
|
|
94
|
-
setIsLoading(true);
|
|
95
|
-
try {
|
|
96
|
-
// Fetch next batchSize number of items:
|
|
97
|
-
let refBefore = iteratorRef.current;
|
|
98
|
-
let newItems = await iteratorRef.current.next(options?.batchSize ?? 10);
|
|
99
|
-
if (options?.transform) {
|
|
100
|
-
newItems = await Promise.all(newItems.map((item) => options.transform(item)));
|
|
101
|
-
}
|
|
102
|
-
if (iteratorRef.current !== refBefore) {
|
|
103
|
-
// If the iterator has changed, we should not update the state
|
|
104
|
-
// This can happen if the iterator was closed and a new one was created
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
emptyResultsRef.current = newItems.length === 0;
|
|
108
|
-
if (newItems.length > 0) {
|
|
109
|
-
let prev = allRef.current;
|
|
110
|
-
let prevHash = new Set(prev.map((x) => x.__context.head));
|
|
111
|
-
let newItemsNoHash = newItems.filter((x) => !prevHash.has(x.__context.head));
|
|
112
|
-
if (newItemsNoHash.length === 0) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const combined = options?.reverse
|
|
116
|
-
? [...newItemsNoHash.reverse(), ...prev]
|
|
117
|
-
: [...prev, ...newItemsNoHash];
|
|
118
|
-
updateAll(combined);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
if (error instanceof ClosedError) {
|
|
123
|
-
// Handle closed database gracefully
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
throw error;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
finally {
|
|
130
|
-
setIsLoading(false);
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
return { items: all, loadMore, isLoading, empty: emptyResultsRef.current };
|
|
134
|
-
};
|
|
135
|
-
//# sourceMappingURL=useLocalPaginated.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useLocalPaginated.js","sourceRoot":"","sources":["../../src/useLocalPaginated.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EACH,WAAW,GAOd,MAAM,mBAAmB,CAAC;AAS3B,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAM7B,EAAoB,EACpB,OAQgB,EAClB,EAAE;IACA,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAoB,EAAE,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,CAAoB,EAAE,CAAC,CAAC;IAC7C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,WAAW,GAAG,MAAM,CAA0C,IAAI,CAAC,CAAC;IAC1E,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEtC,MAAM,SAAS,GAAG,CAAC,QAA2B,EAAE,EAAE;QAC9C,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC;YACrB,OAAO,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,CAAC;QACnC,CAAC;QAED,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;YACjB,IAAI,KAAK,GACL,OAAO,OAAO,CAAC,KAAK,KAAK,SAAS;gBAC9B,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CACP,yCAAyC,EACzC,KAAK,EACL,QAAQ,CAAC,MAAM,CAClB,CAAC;QACN,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;gBACrB,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,QAAkB,CAAC,EAAE,CAAC;oBACrC,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;gBACxD,CAAC;gBACD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,QAAkB,CAAC,CAAC;YACvC,CAAC;QACL,CAAC;QACD,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC;QAE1B,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrB,CAAC,CAAC;IAEF,0DAA0D;IAC1D,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,IAAI,OAAO,EAAE,KAAK,KAAK,IAAI,EAAE,CAAC;YAC9C,OAAO;QACX,CAAC;QACD,MAAM,YAAY,GAAG,GAAG,EAAE;YACtB,IAAI,CAAC;gBACD,kDAAkD;gBAElD,eAAe,CAAC,OAAO,GAAG,KAAK,CAAC;gBAChC,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;gBAC7B,WAAW,CAAC,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,EAAE;oBACzD,KAAK,EAAE,IAAI;oBACX,MAAM,EAAE,KAAK;oBACb,OAAO,EAAE,OAAO,EAAE,OAAc;iBACnC,CAA4C,CAAC,CAAC,aAAa;gBAE5D,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;oBACjB,IAAI,KAAK,GACL,OAAO,OAAO,CAAC,KAAK,KAAK,SAAS;wBAC9B,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC3B,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;gBAC9C,CAAC;gBAED,QAAQ,EAAE,CAAC,CAAC,eAAe;YAC/B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACxD,CAAC;QACL,CAAC,CAAC;QAEF,4CAA4C;QAE5C,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,CAAC,EAAE,CAAC,CAAC;QACX,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC;QAEpB,YAAY,EAAE,CAAC;QAEf,MAAM,YAAY,GAAG,KAAK,EAAE,CAAkC,EAAE,EAAE;YAC9D,wGAAwG;YACxG,IAAI,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,CACrC,MAAM,CAAC,OAAO,EACd,CAAC,CAAC,MAAM,EACR,OAAO,EAAE,KAAK,IAAI,EAAE,EACpB,OAAO,EAAE,OAAO,IAAI,IAAI,CAC3B,CAAC;YACF,OAAO,CAAC,GAAG,CACP,cAAc,EACd,UAAU;gBACN,CAAC,MAAM,KAAK,MAAM,CAAC,OAAO;oBACtB,MAAM,CAAC,MAAM;oBACb,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,EACpC,MAAM,EACN,GAAG,EACH,CAAC,CAAC,MAAM,EACR,MAAM,CAAC,OAAO,CACjB,CAAC;YACF,IACI,MAAM,KAAK,MAAM,CAAC,OAAO;gBACzB,MAAM,CAAC,MAAM;gBACb,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAC7B,CAAC;gBACC,YAAY;YAChB,CAAC;iBAAM,CAAC;gBACJ,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC5D,CAAC;QACL,CAAC,CAAC;QAEF,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QACnD,OAAO,GAAG,EAAE;YACR,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;YACtD,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QACjC,CAAC,CAAC;IACN,CAAC,EAAE;QACC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,WAAW;QACxC,OAAO,EAAE,EAAE;QACX,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,OAAO;KACnB,CAAC,CAAC;IAEH,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QACxB,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,SAAS,IAAI,eAAe,CAAC,OAAO;YAC5D,OAAO;QAEX,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,IAAI,CAAC;YACD,wCAAwC;YACxC,IAAI,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC;YAEpC,IAAI,QAAQ,GAAsB,MAAM,WAAW,CAAC,OAAO,CAAC,IAAI,CAC5D,OAAO,EAAE,SAAS,IAAI,EAAE,CAC3B,CAAC;YAEF,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC;gBACrB,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CACxB,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,SAAU,CAAC,IAAI,CAAC,CAAC,CACnD,CAAC;YACN,CAAC;YAED,IAAI,WAAW,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBACpC,8DAA8D;gBAC9D,uEAAuE;gBACvE,OAAO;YACX,CAAC;YAED,eAAe,CAAC,OAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;YAEhD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,IAAI,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC;gBAC1B,IAAI,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC1D,IAAI,cAAc,GAAG,QAAQ,CAAC,MAAM,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CACzC,CAAC;gBACF,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC9B,OAAO;gBACX,CAAC;gBACD,MAAM,QAAQ,GAAG,OAAO,EAAE,OAAO;oBAC7B,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC;oBACxC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,cAAc,CAAC,CAAC;gBACnC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACxB,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;gBAC/B,oCAAoC;YACxC,CAAC;iBAAM,CAAC;gBACJ,MAAM,KAAK,CAAC;YAChB,CAAC;QACL,CAAC;gBAAS,CAAC;YACP,YAAY,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;IACL,CAAC,CAAC;IAEF,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,CAAC,OAAO,EAAE,CAAC;AAC/E,CAAC,CAAC"}
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useRef } from "react";
|
|
2
|
-
import {
|
|
3
|
-
ClosedError,
|
|
4
|
-
Documents,
|
|
5
|
-
DocumentsChange,
|
|
6
|
-
ResultsIterator,
|
|
7
|
-
SearchRequest,
|
|
8
|
-
SearchRequestIndexed,
|
|
9
|
-
WithContext,
|
|
10
|
-
} from "@peerbit/document";
|
|
11
|
-
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
12
|
-
|
|
13
|
-
type QueryLike = {
|
|
14
|
-
query?: indexerTypes.Query[] | indexerTypes.QueryLike;
|
|
15
|
-
sort?: indexerTypes.Sort[] | indexerTypes.Sort | indexerTypes.SortLike;
|
|
16
|
-
};
|
|
17
|
-
type QueryOptions = { query: QueryLike; id: string };
|
|
18
|
-
|
|
19
|
-
export const useLocalPaginated = <
|
|
20
|
-
T extends Record<string, any>,
|
|
21
|
-
I extends Record<string, any>,
|
|
22
|
-
R extends boolean | undefined = true,
|
|
23
|
-
RT = R extends false ? WithContext<I> : WithContext<T>
|
|
24
|
-
>(
|
|
25
|
-
db?: Documents<T, I>,
|
|
26
|
-
options?: {
|
|
27
|
-
resolve?: R;
|
|
28
|
-
transform?: (result: WithContext<RT>) => Promise<WithContext<RT>>;
|
|
29
|
-
onChanges?: (all: RT[]) => void;
|
|
30
|
-
debounce?: number;
|
|
31
|
-
debug?: boolean | { id: string };
|
|
32
|
-
reverse?: boolean;
|
|
33
|
-
batchSize?: number; // You can set a default batch size here
|
|
34
|
-
} & QueryOptions
|
|
35
|
-
) => {
|
|
36
|
-
const [all, setAll] = useState<WithContext<RT>[]>([]);
|
|
37
|
-
const allRef = useRef<WithContext<RT>[]>([]);
|
|
38
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
39
|
-
const iteratorRef = useRef<ResultsIterator<WithContext<RT>> | null>(null);
|
|
40
|
-
const emptyResultsRef = useRef(false);
|
|
41
|
-
|
|
42
|
-
const updateAll = (combined: WithContext<RT>[]) => {
|
|
43
|
-
if (options?.onChanges) {
|
|
44
|
-
options?.onChanges?.(combined);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (options?.debug) {
|
|
48
|
-
let dbgId =
|
|
49
|
-
typeof options.debug === "boolean"
|
|
50
|
-
? undefined
|
|
51
|
-
: options.debug.id;
|
|
52
|
-
console.log(
|
|
53
|
-
"Loading more items, new combined length",
|
|
54
|
-
dbgId,
|
|
55
|
-
combined.length
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const dedub = new Set<string>();
|
|
60
|
-
for (const item of combined) {
|
|
61
|
-
if ("idString" in item) {
|
|
62
|
-
if (dedub.has(item.idString as string)) {
|
|
63
|
-
throw new Error("Duplicate item found in iterator");
|
|
64
|
-
}
|
|
65
|
-
dedub.add(item.idString as string);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
allRef.current = combined;
|
|
69
|
-
|
|
70
|
-
setAll(combined);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
// Initialize the iterator only once or when query changes
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (!db || db.closed || options?.query === null) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
const initIterator = () => {
|
|
79
|
-
try {
|
|
80
|
-
// Initialize the iterator and load initial batch.
|
|
81
|
-
|
|
82
|
-
emptyResultsRef.current = false;
|
|
83
|
-
iteratorRef.current?.close();
|
|
84
|
-
iteratorRef.current = db.index.iterate(options?.query ?? {}, {
|
|
85
|
-
local: true,
|
|
86
|
-
remote: false,
|
|
87
|
-
resolve: options?.resolve as any,
|
|
88
|
-
}) as any as ResultsIterator<WithContext<RT>>; // TODO types
|
|
89
|
-
|
|
90
|
-
if (options?.debug) {
|
|
91
|
-
let dbgId =
|
|
92
|
-
typeof options.debug === "boolean"
|
|
93
|
-
? undefined
|
|
94
|
-
: options.debug.id;
|
|
95
|
-
console.log("Create new iterator", dbgId);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
loadMore(); // initial load
|
|
99
|
-
} catch (error) {
|
|
100
|
-
console.error("Error initializing iterator", error);
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// Reset state when the db or query changes.
|
|
105
|
-
|
|
106
|
-
console.log("RESET FROM", all.length);
|
|
107
|
-
setAll([]);
|
|
108
|
-
allRef.current = [];
|
|
109
|
-
|
|
110
|
-
initIterator();
|
|
111
|
-
|
|
112
|
-
const handleChange = async (e: CustomEvent<DocumentsChange<T>>) => {
|
|
113
|
-
// while we are iterating, we might get new documents.. so this method inserts them where they should be
|
|
114
|
-
let merged = await db.index.updateResults(
|
|
115
|
-
allRef.current,
|
|
116
|
-
e.detail,
|
|
117
|
-
options?.query || {},
|
|
118
|
-
options?.resolve ?? true
|
|
119
|
-
);
|
|
120
|
-
console.log(
|
|
121
|
-
"merge result",
|
|
122
|
-
"change: " +
|
|
123
|
-
(merged === allRef.current &&
|
|
124
|
-
merged.length &&
|
|
125
|
-
allRef.current.length === 0),
|
|
126
|
-
merged,
|
|
127
|
-
all,
|
|
128
|
-
e.detail,
|
|
129
|
-
allRef.current
|
|
130
|
-
);
|
|
131
|
-
if (
|
|
132
|
-
merged === allRef.current &&
|
|
133
|
-
merged.length &&
|
|
134
|
-
allRef.current.length === 0
|
|
135
|
-
) {
|
|
136
|
-
// no change
|
|
137
|
-
} else {
|
|
138
|
-
updateAll(options?.reverse ? merged.reverse() : merged);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
db.events.addEventListener("change", handleChange);
|
|
143
|
-
return () => {
|
|
144
|
-
db.events.removeEventListener("change", handleChange);
|
|
145
|
-
iteratorRef.current?.close();
|
|
146
|
-
};
|
|
147
|
-
}, [
|
|
148
|
-
db?.closed ? undefined : db?.rootAddress,
|
|
149
|
-
options?.id,
|
|
150
|
-
options?.query,
|
|
151
|
-
options?.resolve,
|
|
152
|
-
]);
|
|
153
|
-
|
|
154
|
-
// Define the loadMore function
|
|
155
|
-
const loadMore = async () => {
|
|
156
|
-
if (!iteratorRef.current || isLoading || emptyResultsRef.current)
|
|
157
|
-
return;
|
|
158
|
-
|
|
159
|
-
setIsLoading(true);
|
|
160
|
-
try {
|
|
161
|
-
// Fetch next batchSize number of items:
|
|
162
|
-
let refBefore = iteratorRef.current;
|
|
163
|
-
|
|
164
|
-
let newItems: WithContext<RT>[] = await iteratorRef.current.next(
|
|
165
|
-
options?.batchSize ?? 10
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
if (options?.transform) {
|
|
169
|
-
newItems = await Promise.all(
|
|
170
|
-
newItems.map((item) => options.transform!(item))
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (iteratorRef.current !== refBefore) {
|
|
175
|
-
// If the iterator has changed, we should not update the state
|
|
176
|
-
// This can happen if the iterator was closed and a new one was created
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
emptyResultsRef.current = newItems.length === 0;
|
|
181
|
-
|
|
182
|
-
if (newItems.length > 0) {
|
|
183
|
-
let prev = allRef.current;
|
|
184
|
-
let prevHash = new Set(prev.map((x) => x.__context.head));
|
|
185
|
-
let newItemsNoHash = newItems.filter(
|
|
186
|
-
(x) => !prevHash.has(x.__context.head)
|
|
187
|
-
);
|
|
188
|
-
if (newItemsNoHash.length === 0) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
const combined = options?.reverse
|
|
192
|
-
? [...newItemsNoHash.reverse(), ...prev]
|
|
193
|
-
: [...prev, ...newItemsNoHash];
|
|
194
|
-
updateAll(combined);
|
|
195
|
-
}
|
|
196
|
-
} catch (error) {
|
|
197
|
-
if (error instanceof ClosedError) {
|
|
198
|
-
// Handle closed database gracefully
|
|
199
|
-
} else {
|
|
200
|
-
throw error;
|
|
201
|
-
}
|
|
202
|
-
} finally {
|
|
203
|
-
setIsLoading(false);
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
return { items: all, loadMore, isLoading, empty: emptyResultsRef.current };
|
|
208
|
-
};
|