@evolu/react 9.0.1-preview.4 → 9.0.1-preview.6
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/README.md +0 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/useIsSsr.d.ts +7 -0
- package/dist/useIsSsr.d.ts.map +1 -0
- package/dist/useIsSsr.js +13 -0
- package/dist/useOwner.d.ts +22 -0
- package/dist/useOwner.d.ts.map +1 -0
- package/dist/useOwner.js +29 -0
- package/dist/useQueries.d.ts +5 -1
- package/dist/useQueries.d.ts.map +1 -1
- package/dist/useQueries.js +11 -5
- package/dist/useQuery.d.ts +5 -5
- package/dist/useQuery.d.ts.map +1 -1
- package/dist/useQuery.js +8 -8
- package/dist/useSyncState.d.ts.map +1 -1
- package/dist/useSyncState.js +7 -4
- package/package.json +9 -7
- package/src/index.ts +3 -2
- package/src/useIsSsr.ts +15 -0
- package/src/useOwner.ts +31 -0
- package/src/useQueries.ts +11 -5
- package/src/useQuery.ts +10 -8
- package/src/useSyncState.ts +8 -8
- package/dist/useAppOwner.d.ts +0 -4
- package/dist/useAppOwner.d.ts.map +0 -1
- package/dist/useAppOwner.js +0 -8
- package/dist/useWasSSR.d.ts +0 -6
- package/dist/useWasSSR.d.ts.map +0 -1
- package/dist/useWasSSR.js +0 -11
- package/src/useAppOwner.ts +0 -13
- package/src/useWasSSR.ts +0 -17
package/README.md
CHANGED
|
@@ -13,5 +13,3 @@ The Evolu community is on [GitHub Discussions](https://github.com/evoluhq/evolu/
|
|
|
13
13
|
To chat with other community members, you can join the [Evolu Discord](https://discord.gg/2J8yyyyxtZ).
|
|
14
14
|
|
|
15
15
|
[](https://twitter.com/evoluhq)
|
|
16
|
-
|
|
17
|
-
TODO: remove this line
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export * from "./createUseEvolu.js";
|
|
2
2
|
export * from "./EvoluContext.js";
|
|
3
3
|
export * from "./EvoluProvider.js";
|
|
4
|
-
export * from "./useAppOwner.js";
|
|
5
4
|
export * from "./useEvolu.js";
|
|
6
5
|
export * from "./useEvoluError.js";
|
|
6
|
+
export * from "./useOwner.js";
|
|
7
7
|
export * from "./useQueries.js";
|
|
8
8
|
export * from "./useQuery.js";
|
|
9
9
|
export * from "./useQuerySubscription.js";
|
|
10
|
-
export * from "./
|
|
10
|
+
export * from "./useIsSsr.js";
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAE1C,cAAc,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export * from "./createUseEvolu.js";
|
|
2
2
|
export * from "./EvoluContext.js";
|
|
3
3
|
export * from "./EvoluProvider.js";
|
|
4
|
-
export * from "./useAppOwner.js";
|
|
5
4
|
export * from "./useEvolu.js";
|
|
6
5
|
export * from "./useEvoluError.js";
|
|
6
|
+
export * from "./useOwner.js";
|
|
7
7
|
export * from "./useQueries.js";
|
|
8
8
|
export * from "./useQuery.js";
|
|
9
9
|
export * from "./useQuerySubscription.js";
|
|
10
|
-
export * from "./useSyncState.js";
|
|
10
|
+
// export * from "./useSyncState.js"; TODO: Update it for the owner-api
|
|
11
|
+
export * from "./useIsSsr.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIsSsr.d.ts","sourceRoot":"","sources":["../src/useIsSsr.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,eAAO,MAAM,QAAQ,QAAO,OAG3B,CAAC"}
|
package/dist/useIsSsr.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { constFalse, constTrue } from "@evolu/common";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
4
|
+
const emptySubscribe = () => () => { };
|
|
5
|
+
/**
|
|
6
|
+
* Avoiding hydration mismatches.
|
|
7
|
+
*
|
|
8
|
+
* @see https://kurtextrem.de/posts/react-uses-hydration
|
|
9
|
+
*/
|
|
10
|
+
export const useIsSsr = () => {
|
|
11
|
+
// TODO: Consider useDeferredValue(isSSRSync);
|
|
12
|
+
return useSyncExternalStore(emptySubscribe, constFalse, constTrue);
|
|
13
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SyncOwner } from "@evolu/common";
|
|
2
|
+
/**
|
|
3
|
+
* React Hook for managing sync owner subscriptions.
|
|
4
|
+
*
|
|
5
|
+
* When the component mounts, it registers the owner for syncing. When the
|
|
6
|
+
* component unmounts or the owner changes, it automatically unregisters.
|
|
7
|
+
*
|
|
8
|
+
* ### Example
|
|
9
|
+
*
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { useOwner } from "@evolu/react";
|
|
12
|
+
*
|
|
13
|
+
* function MyComponent({ shardOwner }: { shardOwner: SyncOwner | null }) {
|
|
14
|
+
* useOwner(shardOwner);
|
|
15
|
+
*
|
|
16
|
+
* // Component will sync with shardOwner while mounted
|
|
17
|
+
* return <div>Syncing with shard...</div>;
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare const useOwner: (owner: SyncOwner | null) => void;
|
|
22
|
+
//# sourceMappingURL=useOwner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useOwner.d.ts","sourceRoot":"","sources":["../src/useOwner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI1C;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,GAAG,IAAI,KAAG,IAOlD,CAAC"}
|
package/dist/useOwner.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { useEvolu } from "./useEvolu.js";
|
|
3
|
+
/**
|
|
4
|
+
* React Hook for managing sync owner subscriptions.
|
|
5
|
+
*
|
|
6
|
+
* When the component mounts, it registers the owner for syncing. When the
|
|
7
|
+
* component unmounts or the owner changes, it automatically unregisters.
|
|
8
|
+
*
|
|
9
|
+
* ### Example
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { useOwner } from "@evolu/react";
|
|
13
|
+
*
|
|
14
|
+
* function MyComponent({ shardOwner }: { shardOwner: SyncOwner | null }) {
|
|
15
|
+
* useOwner(shardOwner);
|
|
16
|
+
*
|
|
17
|
+
* // Component will sync with shardOwner while mounted
|
|
18
|
+
* return <div>Syncing with shard...</div>;
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export const useOwner = (owner) => {
|
|
23
|
+
const evolu = useEvolu();
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (owner == null)
|
|
26
|
+
return;
|
|
27
|
+
return evolu.useOwner(owner);
|
|
28
|
+
}, [evolu, owner]);
|
|
29
|
+
};
|
package/dist/useQueries.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Queries, QueriesToQueryRows, QueriesToQueryRowsPromises, Row } from "@evolu/common/evolu";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* The same as {@link useQuery}, but for many queries.
|
|
4
|
+
*
|
|
5
|
+
* The number of queries must remain stable across renders.
|
|
6
|
+
*/
|
|
3
7
|
export declare const useQueries: <R extends Row, Q extends Queries<R>, OQ extends Queries<R>>(queries: [...Q], options?: Partial<{
|
|
4
8
|
/** Queries that should be only loaded, not subscribed to. */
|
|
5
9
|
readonly once: [...OQ];
|
package/dist/useQueries.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useQueries.d.ts","sourceRoot":"","sources":["../src/useQueries.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,kBAAkB,EAClB,0BAA0B,EAC1B,GAAG,EACJ,MAAM,qBAAqB,CAAC;AAO7B
|
|
1
|
+
{"version":3,"file":"useQueries.d.ts","sourceRoot":"","sources":["../src/useQueries.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,kBAAkB,EAClB,0BAA0B,EAC1B,GAAG,EACJ,MAAM,qBAAqB,CAAC;AAO7B;;;;GAIG;AACH,eAAO,MAAM,UAAU,GACrB,CAAC,SAAS,GAAG,EACb,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,EACpB,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,EAErB,SAAS,CAAC,GAAG,CAAC,CAAC,EACf,UAAS,OAAO,CAAC;IACf,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;IAEvB,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,CACjB,GAAG,0BAA0B,CAAC,CAAC,CAAC,EAChC,GAAG,0BAA0B,CAAC,EAAE,CAAC,CAClC,CAAC;CACH,CAAM,KACN,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,EAAE,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAkBtD,CAAC"}
|
package/dist/useQueries.js
CHANGED
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
import { use, useRef } from "react";
|
|
2
2
|
import { useEvolu } from "./useEvolu.js";
|
|
3
3
|
import { useQuerySubscription } from "./useQuerySubscription.js";
|
|
4
|
-
import {
|
|
5
|
-
/**
|
|
4
|
+
import { useIsSsr } from "./useIsSsr.js";
|
|
5
|
+
/**
|
|
6
|
+
* The same as {@link useQuery}, but for many queries.
|
|
7
|
+
*
|
|
8
|
+
* The number of queries must remain stable across renders.
|
|
9
|
+
*/
|
|
6
10
|
export const useQueries = (queries, options = {}) => {
|
|
7
11
|
const evolu = useEvolu();
|
|
8
12
|
const once = useRef(options).current.once;
|
|
9
13
|
const allQueries = once ? queries.concat(once) : queries;
|
|
10
|
-
const wasSSR =
|
|
14
|
+
const wasSSR = useIsSsr();
|
|
11
15
|
if (wasSSR) {
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
13
16
|
if (!options.promises)
|
|
14
|
-
evolu.loadQueries(allQueries);
|
|
17
|
+
void evolu.loadQueries(allQueries);
|
|
15
18
|
}
|
|
16
19
|
else {
|
|
17
20
|
if (options.promises)
|
|
18
21
|
options.promises.map(use);
|
|
22
|
+
// No waterfall: loadQuery batches all queries in the same microtask,
|
|
23
|
+
// so React suspends once and all promises resolve together.
|
|
19
24
|
else
|
|
20
25
|
evolu.loadQueries(allQueries).map(use);
|
|
21
26
|
}
|
|
22
27
|
return allQueries.map((query, i) =>
|
|
28
|
+
// Safe until the number of queries is stable.
|
|
23
29
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
24
30
|
useQuerySubscription(query, { once: i > queries.length - 1 }));
|
|
25
31
|
};
|
package/dist/useQuery.d.ts
CHANGED
|
@@ -7,6 +7,10 @@ import { Query, QueryRows, Row } from "@evolu/common/evolu";
|
|
|
7
7
|
* {@link useQuery} blocks rendering until loading is completed. To avoid loading
|
|
8
8
|
* waterfall with more queries, use {@link useQueries}.
|
|
9
9
|
*
|
|
10
|
+
* The `promise` option allows preloading queries before rendering, which can be
|
|
11
|
+
* useful for complex queries that might take noticeable time even with local
|
|
12
|
+
* data. However, this is rarely needed as local queries are typically fast.
|
|
13
|
+
*
|
|
10
14
|
* ### Example
|
|
11
15
|
*
|
|
12
16
|
* ```ts
|
|
@@ -19,12 +23,8 @@ import { Query, QueryRows, Row } from "@evolu/common/evolu";
|
|
|
19
23
|
* // Get all rows, but without subscribing to changes.
|
|
20
24
|
* const rows = useQuery(allTodos, { once: true });
|
|
21
25
|
*
|
|
22
|
-
* //
|
|
23
|
-
* const allTodos = evolu.createQuery((db) =>
|
|
24
|
-
* db.selectFrom("todo").selectAll(),
|
|
25
|
-
* );
|
|
26
|
+
* // Preload a query (rarely needed).
|
|
26
27
|
* const allTodosPromise = evolu.loadQuery(allTodos);
|
|
27
|
-
* // Use prefetched rows.
|
|
28
28
|
* const rows = useQuery(allTodos, { promise: allTodosPromise });
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
package/dist/useQuery.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useQuery.d.ts","sourceRoot":"","sources":["../src/useQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAO5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,GAAG,EACpC,OAAO,KAAK,CAAC,CAAC,CAAC,EACf,UAAS,OAAO,CAAC;IACf,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAEvB,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;CACzC,CAAM,KACN,SAAS,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"useQuery.d.ts","sourceRoot":"","sources":["../src/useQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAO5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,GAAG,EACpC,OAAO,KAAK,CAAC,CAAC,CAAC,EACf,UAAS,OAAO,CAAC;IACf,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAEvB,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;CACzC,CAAM,KACN,SAAS,CAAC,CAAC,CAWb,CAAC"}
|
package/dist/useQuery.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { use } from "react";
|
|
2
2
|
import { useEvolu } from "./useEvolu.js";
|
|
3
3
|
import { useQuerySubscription } from "./useQuerySubscription.js";
|
|
4
|
-
import {
|
|
4
|
+
import { useIsSsr } from "./useIsSsr.js";
|
|
5
5
|
/**
|
|
6
6
|
* Load and subscribe to the Query, and return an object with `rows` and `row`
|
|
7
7
|
* properties that are automatically updated when data changes.
|
|
@@ -10,6 +10,10 @@ import { useWasSSR } from "./useWasSSR.js";
|
|
|
10
10
|
* {@link useQuery} blocks rendering until loading is completed. To avoid loading
|
|
11
11
|
* waterfall with more queries, use {@link useQueries}.
|
|
12
12
|
*
|
|
13
|
+
* The `promise` option allows preloading queries before rendering, which can be
|
|
14
|
+
* useful for complex queries that might take noticeable time even with local
|
|
15
|
+
* data. However, this is rarely needed as local queries are typically fast.
|
|
16
|
+
*
|
|
13
17
|
* ### Example
|
|
14
18
|
*
|
|
15
19
|
* ```ts
|
|
@@ -22,19 +26,15 @@ import { useWasSSR } from "./useWasSSR.js";
|
|
|
22
26
|
* // Get all rows, but without subscribing to changes.
|
|
23
27
|
* const rows = useQuery(allTodos, { once: true });
|
|
24
28
|
*
|
|
25
|
-
* //
|
|
26
|
-
* const allTodos = evolu.createQuery((db) =>
|
|
27
|
-
* db.selectFrom("todo").selectAll(),
|
|
28
|
-
* );
|
|
29
|
+
* // Preload a query (rarely needed).
|
|
29
30
|
* const allTodosPromise = evolu.loadQuery(allTodos);
|
|
30
|
-
* // Use prefetched rows.
|
|
31
31
|
* const rows = useQuery(allTodos, { promise: allTodosPromise });
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
export const useQuery = (query, options = {}) => {
|
|
35
35
|
const evolu = useEvolu();
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
36
|
+
const isSSR = useIsSsr();
|
|
37
|
+
if (isSSR) {
|
|
38
38
|
if (!options.promise)
|
|
39
39
|
void evolu.loadQuery(query);
|
|
40
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSyncState.d.ts","sourceRoot":"","sources":["../src/useSyncState.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"useSyncState.d.ts","sourceRoot":"","sources":["../src/useSyncState.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,8CAA8C;AAC9C,eAAO,MAAM,YAAY,QAAO,SAQ/B,CAAC"}
|
package/dist/useSyncState.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { initialSyncState } from "@evolu/common/evolu";
|
|
2
|
-
import { useSyncExternalStore } from "react";
|
|
3
1
|
import { useEvolu } from "./useEvolu.js";
|
|
4
2
|
/** Subscribe to {@link SyncState} changes. */
|
|
5
3
|
export const useSyncState = () => {
|
|
6
|
-
const
|
|
7
|
-
return useSyncExternalStore(
|
|
4
|
+
const _evolu = useEvolu();
|
|
5
|
+
// return useSyncExternalStore(
|
|
6
|
+
// evolu.subscribeSyncState,
|
|
7
|
+
// evolu.getSyncState,
|
|
8
|
+
// () => initialSyncState,
|
|
9
|
+
// );
|
|
10
|
+
throw new Error("TODO");
|
|
8
11
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evolu/react",
|
|
3
|
-
"version": "9.0.1-preview.
|
|
3
|
+
"version": "9.0.1-preview.6",
|
|
4
4
|
"description": "Evolu for React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"evolu",
|
|
@@ -30,16 +30,18 @@
|
|
|
30
30
|
"README.md"
|
|
31
31
|
],
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@types/react
|
|
34
|
-
"react": "
|
|
33
|
+
"@types/react": "~19.1.13",
|
|
34
|
+
"@types/react-dom": "~19.1.9",
|
|
35
|
+
"react": "19.1.0",
|
|
36
|
+
"shx": "^0.4.0",
|
|
35
37
|
"typescript": "^5.9.2",
|
|
36
|
-
"vitest": "^
|
|
37
|
-
"@evolu/common": "6.0.1-preview.
|
|
38
|
+
"vitest": "^4.0.4",
|
|
39
|
+
"@evolu/common": "6.0.1-preview.22",
|
|
38
40
|
"@evolu/tsconfig": "0.0.2"
|
|
39
41
|
},
|
|
40
42
|
"peerDependencies": {
|
|
41
|
-
"@evolu/common": "^6.0.1-preview.
|
|
42
|
-
"react": "
|
|
43
|
+
"@evolu/common": "^6.0.1-preview.22",
|
|
44
|
+
"react": ">=19"
|
|
43
45
|
},
|
|
44
46
|
"publishConfig": {
|
|
45
47
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export * from "./createUseEvolu.js";
|
|
2
2
|
export * from "./EvoluContext.js";
|
|
3
3
|
export * from "./EvoluProvider.js";
|
|
4
|
-
export * from "./useAppOwner.js";
|
|
5
4
|
export * from "./useEvolu.js";
|
|
6
5
|
export * from "./useEvoluError.js";
|
|
6
|
+
export * from "./useOwner.js";
|
|
7
7
|
export * from "./useQueries.js";
|
|
8
8
|
export * from "./useQuery.js";
|
|
9
9
|
export * from "./useQuerySubscription.js";
|
|
10
|
-
export * from "./useSyncState.js";
|
|
10
|
+
// export * from "./useSyncState.js"; TODO: Update it for the owner-api
|
|
11
|
+
export * from "./useIsSsr.js";
|
package/src/useIsSsr.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { constFalse, constTrue } from "@evolu/common";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
5
|
+
const emptySubscribe = () => () => {};
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Avoiding hydration mismatches.
|
|
9
|
+
*
|
|
10
|
+
* @see https://kurtextrem.de/posts/react-uses-hydration
|
|
11
|
+
*/
|
|
12
|
+
export const useIsSsr = (): boolean => {
|
|
13
|
+
// TODO: Consider useDeferredValue(isSSRSync);
|
|
14
|
+
return useSyncExternalStore(emptySubscribe, constFalse, constTrue);
|
|
15
|
+
};
|
package/src/useOwner.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SyncOwner } from "@evolu/common";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import { useEvolu } from "./useEvolu.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* React Hook for managing sync owner subscriptions.
|
|
7
|
+
*
|
|
8
|
+
* When the component mounts, it registers the owner for syncing. When the
|
|
9
|
+
* component unmounts or the owner changes, it automatically unregisters.
|
|
10
|
+
*
|
|
11
|
+
* ### Example
|
|
12
|
+
*
|
|
13
|
+
* ```tsx
|
|
14
|
+
* import { useOwner } from "@evolu/react";
|
|
15
|
+
*
|
|
16
|
+
* function MyComponent({ shardOwner }: { shardOwner: SyncOwner | null }) {
|
|
17
|
+
* useOwner(shardOwner);
|
|
18
|
+
*
|
|
19
|
+
* // Component will sync with shardOwner while mounted
|
|
20
|
+
* return <div>Syncing with shard...</div>;
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export const useOwner = (owner: SyncOwner | null): void => {
|
|
25
|
+
const evolu = useEvolu();
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (owner == null) return;
|
|
29
|
+
return evolu.useOwner(owner);
|
|
30
|
+
}, [evolu, owner]);
|
|
31
|
+
};
|
package/src/useQueries.ts
CHANGED
|
@@ -8,9 +8,13 @@ import { use, useRef } from "react";
|
|
|
8
8
|
import { useEvolu } from "./useEvolu.js";
|
|
9
9
|
import type { useQuery } from "./useQuery.js";
|
|
10
10
|
import { useQuerySubscription } from "./useQuerySubscription.js";
|
|
11
|
-
import {
|
|
11
|
+
import { useIsSsr } from "./useIsSsr.js";
|
|
12
12
|
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* The same as {@link useQuery}, but for many queries.
|
|
15
|
+
*
|
|
16
|
+
* The number of queries must remain stable across renders.
|
|
17
|
+
*/
|
|
14
18
|
export const useQueries = <
|
|
15
19
|
R extends Row,
|
|
16
20
|
Q extends Queries<R>,
|
|
@@ -31,15 +35,17 @@ export const useQueries = <
|
|
|
31
35
|
const evolu = useEvolu();
|
|
32
36
|
const once = useRef(options).current.once;
|
|
33
37
|
const allQueries = once ? queries.concat(once) : queries;
|
|
34
|
-
const wasSSR =
|
|
38
|
+
const wasSSR = useIsSsr();
|
|
35
39
|
if (wasSSR) {
|
|
36
|
-
|
|
37
|
-
if (!options.promises) evolu.loadQueries(allQueries);
|
|
40
|
+
if (!options.promises) void evolu.loadQueries(allQueries);
|
|
38
41
|
} else {
|
|
39
42
|
if (options.promises) options.promises.map(use);
|
|
43
|
+
// No waterfall: loadQuery batches all queries in the same microtask,
|
|
44
|
+
// so React suspends once and all promises resolve together.
|
|
40
45
|
else evolu.loadQueries(allQueries).map(use);
|
|
41
46
|
}
|
|
42
47
|
return allQueries.map((query, i) =>
|
|
48
|
+
// Safe until the number of queries is stable.
|
|
43
49
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
44
50
|
useQuerySubscription(query, { once: i > queries.length - 1 }),
|
|
45
51
|
) as never;
|
package/src/useQuery.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { use } from "react";
|
|
|
3
3
|
import { useEvolu } from "./useEvolu.js";
|
|
4
4
|
import type { useQueries } from "./useQueries.js";
|
|
5
5
|
import { useQuerySubscription } from "./useQuerySubscription.js";
|
|
6
|
-
import {
|
|
6
|
+
import { useIsSsr } from "./useIsSsr.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Load and subscribe to the Query, and return an object with `rows` and `row`
|
|
@@ -13,6 +13,10 @@ import { useWasSSR } from "./useWasSSR.js";
|
|
|
13
13
|
* {@link useQuery} blocks rendering until loading is completed. To avoid loading
|
|
14
14
|
* waterfall with more queries, use {@link useQueries}.
|
|
15
15
|
*
|
|
16
|
+
* The `promise` option allows preloading queries before rendering, which can be
|
|
17
|
+
* useful for complex queries that might take noticeable time even with local
|
|
18
|
+
* data. However, this is rarely needed as local queries are typically fast.
|
|
19
|
+
*
|
|
16
20
|
* ### Example
|
|
17
21
|
*
|
|
18
22
|
* ```ts
|
|
@@ -25,12 +29,8 @@ import { useWasSSR } from "./useWasSSR.js";
|
|
|
25
29
|
* // Get all rows, but without subscribing to changes.
|
|
26
30
|
* const rows = useQuery(allTodos, { once: true });
|
|
27
31
|
*
|
|
28
|
-
* //
|
|
29
|
-
* const allTodos = evolu.createQuery((db) =>
|
|
30
|
-
* db.selectFrom("todo").selectAll(),
|
|
31
|
-
* );
|
|
32
|
+
* // Preload a query (rarely needed).
|
|
32
33
|
* const allTodosPromise = evolu.loadQuery(allTodos);
|
|
33
|
-
* // Use prefetched rows.
|
|
34
34
|
* const rows = useQuery(allTodos, { promise: allTodosPromise });
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
@@ -45,11 +45,13 @@ export const useQuery = <R extends Row>(
|
|
|
45
45
|
}> = {},
|
|
46
46
|
): QueryRows<R> => {
|
|
47
47
|
const evolu = useEvolu();
|
|
48
|
-
const
|
|
49
|
-
|
|
48
|
+
const isSSR = useIsSsr();
|
|
49
|
+
|
|
50
|
+
if (isSSR) {
|
|
50
51
|
if (!options.promise) void evolu.loadQuery(query);
|
|
51
52
|
} else {
|
|
52
53
|
use(options.promise ?? evolu.loadQuery(query));
|
|
53
54
|
}
|
|
55
|
+
|
|
54
56
|
return useQuerySubscription(query, options);
|
|
55
57
|
};
|
package/src/useSyncState.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { SyncState
|
|
2
|
-
import { useSyncExternalStore } from "react";
|
|
1
|
+
import { SyncState } from "@evolu/common/evolu";
|
|
3
2
|
import { useEvolu } from "./useEvolu.js";
|
|
4
3
|
|
|
5
4
|
/** Subscribe to {@link SyncState} changes. */
|
|
6
5
|
export const useSyncState = (): SyncState => {
|
|
7
|
-
const
|
|
8
|
-
return useSyncExternalStore(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
);
|
|
6
|
+
const _evolu = useEvolu();
|
|
7
|
+
// return useSyncExternalStore(
|
|
8
|
+
// evolu.subscribeSyncState,
|
|
9
|
+
// evolu.getSyncState,
|
|
10
|
+
// () => initialSyncState,
|
|
11
|
+
// );
|
|
12
|
+
throw new Error("TODO");
|
|
13
13
|
};
|
package/dist/useAppOwner.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useAppOwner.d.ts","sourceRoot":"","sources":["../src/useAppOwner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,eAAe,CAAC;AAIpD,6CAA6C;AAC7C,eAAO,MAAM,WAAW,QAAO,QAAQ,GAAG,IAOzC,CAAC"}
|
package/dist/useAppOwner.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { constNull } from "@evolu/common";
|
|
2
|
-
import { useSyncExternalStore } from "react";
|
|
3
|
-
import { useEvolu } from "./useEvolu.js";
|
|
4
|
-
/** Subscribe to {@link AppOwner} changes. */
|
|
5
|
-
export const useAppOwner = () => {
|
|
6
|
-
const evolu = useEvolu();
|
|
7
|
-
return useSyncExternalStore(evolu.subscribeAppOwner, evolu.getAppOwner, constNull);
|
|
8
|
-
};
|
package/dist/useWasSSR.d.ts
DELETED
package/dist/useWasSSR.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useWasSSR.d.ts","sourceRoot":"","sources":["../src/useWasSSR.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,eAAO,MAAM,SAAS,QAAO,OAO5B,CAAC"}
|
package/dist/useWasSSR.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { useRef, useSyncExternalStore } from "react";
|
|
2
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
3
|
-
const emptySubscribe = () => () => { };
|
|
4
|
-
/**
|
|
5
|
-
* "Unlike the typeof window hack, this ensures that the server and hydration
|
|
6
|
-
* sees the same thing."
|
|
7
|
-
*/
|
|
8
|
-
export const useWasSSR = () => {
|
|
9
|
-
const ref = useRef(false);
|
|
10
|
-
return useSyncExternalStore(emptySubscribe, () => ref.current, () => (ref.current = true));
|
|
11
|
-
};
|
package/src/useAppOwner.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { AppOwner, constNull } from "@evolu/common";
|
|
2
|
-
import { useSyncExternalStore } from "react";
|
|
3
|
-
import { useEvolu } from "./useEvolu.js";
|
|
4
|
-
|
|
5
|
-
/** Subscribe to {@link AppOwner} changes. */
|
|
6
|
-
export const useAppOwner = (): AppOwner | null => {
|
|
7
|
-
const evolu = useEvolu();
|
|
8
|
-
return useSyncExternalStore(
|
|
9
|
-
evolu.subscribeAppOwner,
|
|
10
|
-
evolu.getAppOwner,
|
|
11
|
-
constNull,
|
|
12
|
-
);
|
|
13
|
-
};
|
package/src/useWasSSR.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { useRef, useSyncExternalStore } from "react";
|
|
2
|
-
|
|
3
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
4
|
-
const emptySubscribe = () => () => {};
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* "Unlike the typeof window hack, this ensures that the server and hydration
|
|
8
|
-
* sees the same thing."
|
|
9
|
-
*/
|
|
10
|
-
export const useWasSSR = (): boolean => {
|
|
11
|
-
const ref = useRef(false);
|
|
12
|
-
return useSyncExternalStore(
|
|
13
|
-
emptySubscribe,
|
|
14
|
-
() => ref.current,
|
|
15
|
-
() => (ref.current = true),
|
|
16
|
-
);
|
|
17
|
-
};
|