@electric-sql/react 0.3.2 → 0.3.4
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 +1 -1
- package/dist/cjs/index.cjs +17 -15
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.browser.mjs +1 -1
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +13 -15
- package/dist/index.legacy-esm.js +18 -16
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +18 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/react-hooks.tsx +54 -45
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Add `useShape` to a component
|
|
|
20
20
|
import { useShape } from "@electric-sql/react"
|
|
21
21
|
|
|
22
22
|
export default function MyComponent () {
|
|
23
|
-
const { isUpToDate, data
|
|
23
|
+
const { isUpToDate, data } = useShape({
|
|
24
24
|
url: "http://my-api.com/shape/foo",
|
|
25
25
|
})
|
|
26
26
|
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -133,21 +133,23 @@ function useShape(_a) {
|
|
|
133
133
|
]);
|
|
134
134
|
const shapeStream = getShapeStream(options);
|
|
135
135
|
const shape = getShape(shapeStream);
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
136
|
+
const useShapeData = import_react.default.useMemo(() => {
|
|
137
|
+
let latestShapeData = parseShapeData(shape);
|
|
138
|
+
const getSnapshot = () => latestShapeData;
|
|
139
|
+
const subscribe = (onStoreChange) => shapeSubscribe(shape, () => {
|
|
140
|
+
latestShapeData = parseShapeData(shape);
|
|
141
|
+
onStoreChange();
|
|
142
|
+
});
|
|
143
|
+
return () => {
|
|
144
|
+
return (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
145
|
+
subscribe,
|
|
146
|
+
getSnapshot,
|
|
147
|
+
getSnapshot,
|
|
148
|
+
selector
|
|
149
|
+
);
|
|
150
|
+
};
|
|
151
|
+
}, [shape, selector]);
|
|
152
|
+
return useShapeData();
|
|
151
153
|
}
|
|
152
154
|
// Annotate the CommonJS export names for ESM import in node:
|
|
153
155
|
0 && (module.exports = {
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts","../../src/react-hooks.tsx"],"sourcesContent":["export * from './react-hooks'\n","import {\n
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts","../../src/react-hooks.tsx"],"sourcesContent":["export * from './react-hooks'\n","import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape<T extends Row = Row>(\n options: ShapeStreamOptions\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n return JSON.stringify(options, Object.keys(options).sort())\n}\n\nexport function getShapeStream<T extends Row = Row>(\n options: ShapeStreamOptions\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return\n if (streamCache.has(shapeHash)) {\n // Return the ShapeStream\n return streamCache.get(shapeHash)! as ShapeStream<T>\n } else {\n const newShapeStream = new ShapeStream<T>(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)! as Shape<T>\n } else {\n const newShape = new Shape<T>(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\nexport interface UseShapeResult<T extends Row = Row> {\n /**\n * The array of rows that make up the Shape.\n * @type {T[]}\n */\n data: T[]\n /**\n * The Shape instance used by this useShape\n * @type {Shape<T>}\n */\n shape: Shape<T>\n error: Shape<T>[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row, Selection>\n extends ShapeStreamOptions {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row = Row,\n Selection = UseShapeResult<SourceData>,\n>({\n selector = identity as (arg: UseShapeResult<SourceData>) => Selection,\n ...options\n}: UseShapeOptions<SourceData, Selection>): Selection {\n const shapeStream = getShapeStream<SourceData>(options as ShapeStreamOptions)\n const shape = getShape<SourceData>(shapeStream)\n\n const useShapeData = React.useMemo(() => {\n let latestShapeData = parseShapeData(shape)\n const getSnapshot = () => latestShapeData\n const subscribe = (onStoreChange: () => void) =>\n shapeSubscribe(shape, () => {\n latestShapeData = parseShapeData(shape)\n onStoreChange()\n })\n\n return () => {\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getSnapshot,\n selector\n )\n }\n }, [shape, selector])\n\n return useShapeData()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAKO;AACP,mBAAkB;AAClB,2BAAiD;AAEjD,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,SAAsB,aACpB,SACmB;AAAA;AACnB,UAAM,cAAc,eAAkB,OAAO;AAC7C,UAAM,QAAQ,SAAY,WAAW;AACrC,UAAM,MAAM;AACZ,WAAO;AAAA,EACT;AAAA;AAEO,SAAS,kBAAkB,SAAqC;AACrE,SAAO,KAAK,UAAU,SAAS,OAAO,KAAK,OAAO,EAAE,KAAK,CAAC;AAC5D;AAEO,SAAS,eACd,SACgB;AAChB,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,0BAAe,OAAO;AAEjD,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAwB,aAAuC;AAE7E,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,oBAAS,WAAW;AAEzC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAqBA,SAAS,eAA8B,OAAiB,UAAsB;AAC5E,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAA8B,OAAoC;AACzE,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,SAAS,SAAY,KAAW;AAC9B,SAAO;AACT;AAOO,SAAS,SAGd,IAGoD;AAHpD,eACA;AAAA,eAAW;AAAA,EA5Gb,IA2GE,IAEG,oBAFH,IAEG;AAAA,IADH;AAAA;AAGA,QAAM,cAAc,eAA2B,OAA6B;AAC5E,QAAM,QAAQ,SAAqB,WAAW;AAE9C,QAAM,eAAe,aAAAA,QAAM,QAAQ,MAAM;AACvC,QAAI,kBAAkB,eAAe,KAAK;AAC1C,UAAM,cAAc,MAAM;AAC1B,UAAM,YAAY,CAAC,kBACjB,eAAe,OAAO,MAAM;AAC1B,wBAAkB,eAAe,KAAK;AACtC,oBAAc;AAAA,IAChB,CAAC;AAEH,WAAO,MAAM;AACX,iBAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,CAAC;AAEpB,SAAO,aAAa;AACtB;","names":["React"]}
|
package/dist/index.browser.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var u=Object.getOwnPropertySymbols;var
|
|
1
|
+
var u=Object.getOwnPropertySymbols;var x=Object.prototype.hasOwnProperty,d=Object.prototype.propertyIsEnumerable;var T=(e,t)=>{var a={};for(var r in e)x.call(e,r)&&t.indexOf(r)<0&&(a[r]=e[r]);if(e!=null&&u)for(var r of u(e))t.indexOf(r)<0&&d.call(e,r)&&(a[r]=e[r]);return a};var l=(e,t,a)=>new Promise((r,p)=>{var s=o=>{try{n(a.next(o))}catch(S){p(S)}},h=o=>{try{n(a.throw(o))}catch(S){p(S)}},n=o=>o.done?r(o.value):Promise.resolve(o.value).then(s,h);n((a=a.apply(e,t)).next())});import{Shape as D,ShapeStream as b}from"@electric-sql/client";import O from"react";import{useSyncExternalStoreWithSelector as U}from"use-sync-external-store/with-selector.js";var c=new Map,i=new Map;function J(e){return l(this,null,function*(){let t=w(e),a=R(t);return yield a.value,a})}function g(e){return JSON.stringify(e,Object.keys(e).sort())}function w(e){let t=g(e);if(c.has(t))return c.get(t);{let a=new b(e);return c.set(t,a),a}}function R(e){if(i.has(e))return i.get(e);{let t=new D(e);return i.set(e,t),t}}function v(e,t){let a=e.subscribe(t);return()=>{a()}}function m(e){return{data:[...e.valueSync.values()],isUpToDate:e.isUpToDate,isError:e.error!==!1,shape:e,error:e.error}}function y(e){return e}function N(a){var r=a,{selector:e=y}=r,t=T(r,["selector"]);let p=w(t),s=R(p);return O.useMemo(()=>{let n=m(s),o=()=>n,S=f=>v(s,()=>{n=m(s),f()});return()=>U(S,o,o,e)},[s,e])()}export{R as getShape,w as getShapeStream,J as preloadShape,g as sortedOptionsHash,N as useShape};
|
|
2
2
|
//# sourceMappingURL=index.browser.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape<T extends Row = Row>(\n options: ShapeStreamOptions\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n return JSON.stringify(options, Object.keys(options).sort())\n}\n\nexport function getShapeStream<T extends Row = Row>(\n options: ShapeStreamOptions\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return\n if (streamCache.has(shapeHash)) {\n // Return the ShapeStream\n return streamCache.get(shapeHash)! as ShapeStream<T>\n } else {\n const newShapeStream = new ShapeStream<T>(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)! as Shape<T>\n } else {\n const newShape = new Shape<T>(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\nexport interface UseShapeResult<T extends Row = Row> {\n /**\n * The array of rows that make up the Shape.\n * @type {T[]}\n */\n data: T[]\n /**\n * The Shape instance used by this useShape\n * @type {Shape<T>}\n */\n shape: Shape<T>\n error: Shape<T>[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row, Selection>\n extends ShapeStreamOptions {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row = Row,\n Selection = UseShapeResult<SourceData>,\n>({\n selector = identity as (arg: UseShapeResult<SourceData>) => Selection,\n ...options\n}: UseShapeOptions<SourceData, Selection>): Selection {\n const shapeStream = getShapeStream<SourceData>(options as ShapeStreamOptions)\n const shape = getShape<SourceData>(shapeStream)\n\n const useShapeData = React.useMemo(() => {\n let latestShapeData = parseShapeData(shape)\n const getSnapshot = () => latestShapeData\n const subscribe = (onStoreChange: () => void) =>\n shapeSubscribe(shape, () => {\n latestShapeData = parseShapeData(shape)\n onStoreChange()\n })\n\n return () => {\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getSnapshot,\n selector\n )\n }\n }, [shape, selector])\n\n return useShapeData()\n}\n"],"mappings":"geAAA,OACE,SAAAA,EACA,eAAAC,MAGK,uBACP,OAAOC,MAAW,QAClB,OAAS,oCAAAC,MAAwC,2CAEjD,IAAMC,EAAc,IAAI,IAClBC,EAAa,IAAI,IAEvB,SAAsBC,EACpBC,EACmB,QAAAC,EAAA,sBACnB,IAAMC,EAAcC,EAAkBH,CAAO,EACvCI,EAAQC,EAAYH,CAAW,EACrC,aAAME,EAAM,MACLA,CACT,GAEO,SAASE,EAAkBN,EAAqC,CACrE,OAAO,KAAK,UAAUA,EAAS,OAAO,KAAKA,CAAO,EAAE,KAAK,CAAC,CAC5D,CAEO,SAASG,EACdH,EACgB,CAChB,IAAMO,EAAYD,EAAkBN,CAAO,EAG3C,GAAIH,EAAY,IAAIU,CAAS,EAE3B,OAAOV,EAAY,IAAIU,CAAS,EAC3B,CACL,IAAMC,EAAiB,IAAIC,EAAeT,CAAO,EAEjD,OAAAH,EAAY,IAAIU,EAAWC,CAAc,EAGlCA,CACT,CACF,CAEO,SAASH,EAAwBH,EAAuC,CAE7E,GAAIJ,EAAW,IAAII,CAAW,EAE5B,OAAOJ,EAAW,IAAII,CAAW,EAC5B,CACL,IAAMQ,EAAW,IAAIC,EAAST,CAAW,EAEzC,OAAAJ,EAAW,IAAII,EAAaQ,CAAQ,EAG7BA,CACT,CACF,CAqBA,SAASE,EAA8BR,EAAiBS,EAAsB,CAC5E,IAAMC,EAAcV,EAAM,UAAUS,CAAQ,EAC5C,MAAO,IAAM,CACXC,EAAY,CACd,CACF,CAEA,SAASC,EAA8BX,EAAoC,CACzE,MAAO,CACL,KAAM,CAAC,GAAGA,EAAM,UAAU,OAAO,CAAC,EAClC,WAAYA,EAAM,WAClB,QAASA,EAAM,QAAU,GACzB,MAAAA,EACA,MAAOA,EAAM,KACf,CACF,CAEA,SAASY,EAAYC,EAAW,CAC9B,OAAOA,CACT,CAOO,SAASC,EAGdC,EAGoD,CAHpD,IAAAC,EAAAD,EACA,UAAAE,EAAWL,CA5Gb,EA2GEI,EAEGpB,EAAAsB,EAFHF,EAEG,CADH,aAGA,IAAMlB,EAAcC,EAA2BH,CAA6B,EACtEI,EAAQC,EAAqBH,CAAW,EAqB9C,OAnBqBqB,EAAM,QAAQ,IAAM,CACvC,IAAIC,EAAkBT,EAAeX,CAAK,EACpCqB,EAAc,IAAMD,EACpBE,EAAaC,GACjBf,EAAeR,EAAO,IAAM,CAC1BoB,EAAkBT,EAAeX,CAAK,EACtCuB,EAAc,CAChB,CAAC,EAEH,MAAO,IACEC,EACLF,EACAD,EACAA,EACAJ,CACF,CAEJ,EAAG,CAACjB,EAAOiB,CAAQ,CAAC,EAEA,CACtB","names":["Shape","ShapeStream","React","useSyncExternalStoreWithSelector","streamCache","shapeCache","preloadShape","options","__async","shapeStream","getShapeStream","shape","getShape","sortedOptionsHash","shapeHash","newShapeStream","ShapeStream","newShape","Shape","shapeSubscribe","callback","unsubscribe","parseShapeData","identity","arg","useShape","_a","_b","selector","__objRest","React","latestShapeData","getSnapshot","subscribe","onStoreChange","useSyncExternalStoreWithSelector"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,32 +1,30 @@
|
|
|
1
|
-
import { ShapeStreamOptions, Shape, ShapeStream
|
|
1
|
+
import { Row, ShapeStreamOptions, Shape, ShapeStream } from '@electric-sql/client';
|
|
2
2
|
|
|
3
|
-
declare function preloadShape(options: ShapeStreamOptions): Promise<Shape
|
|
3
|
+
declare function preloadShape<T extends Row = Row>(options: ShapeStreamOptions): Promise<Shape<T>>;
|
|
4
4
|
declare function sortedOptionsHash(options: ShapeStreamOptions): string;
|
|
5
|
-
declare function getShapeStream(options: ShapeStreamOptions): ShapeStream
|
|
6
|
-
declare function getShape(shapeStream: ShapeStream): Shape
|
|
7
|
-
interface UseShapeResult {
|
|
5
|
+
declare function getShapeStream<T extends Row = Row>(options: ShapeStreamOptions): ShapeStream<T>;
|
|
6
|
+
declare function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T>;
|
|
7
|
+
interface UseShapeResult<T extends Row = Row> {
|
|
8
8
|
/**
|
|
9
9
|
* The array of rows that make up the Shape.
|
|
10
|
-
* @type {
|
|
10
|
+
* @type {T[]}
|
|
11
11
|
*/
|
|
12
|
-
data:
|
|
13
|
-
[key: string]: Value;
|
|
14
|
-
}[];
|
|
12
|
+
data: T[];
|
|
15
13
|
/**
|
|
16
14
|
* The Shape instance used by this useShape
|
|
17
|
-
* @type
|
|
15
|
+
* @type {Shape<T>}
|
|
18
16
|
*/
|
|
19
|
-
shape: Shape
|
|
20
|
-
error: Shape[`error`];
|
|
17
|
+
shape: Shape<T>;
|
|
18
|
+
error: Shape<T>[`error`];
|
|
21
19
|
isError: boolean;
|
|
22
20
|
/**
|
|
23
21
|
* Has the ShapeStream caught up with the replication log from Postgres.
|
|
24
22
|
*/
|
|
25
23
|
isUpToDate: boolean;
|
|
26
24
|
}
|
|
27
|
-
interface UseShapeOptions<Selection> extends ShapeStreamOptions {
|
|
28
|
-
selector?: (value: UseShapeResult) => Selection;
|
|
25
|
+
interface UseShapeOptions<SourceData extends Row, Selection> extends ShapeStreamOptions {
|
|
26
|
+
selector?: (value: UseShapeResult<SourceData>) => Selection;
|
|
29
27
|
}
|
|
30
|
-
declare function useShape<Selection = UseShapeResult
|
|
28
|
+
declare function useShape<SourceData extends Row = Row, Selection = UseShapeResult<SourceData>>({ selector, ...options }: UseShapeOptions<SourceData, Selection>): Selection;
|
|
31
29
|
|
|
32
30
|
export { type UseShapeResult, getShape, getShapeStream, preloadShape, sortedOptionsHash, useShape };
|
package/dist/index.legacy-esm.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
Shape,
|
|
20
20
|
ShapeStream
|
|
21
21
|
} from "@electric-sql/client";
|
|
22
|
-
import React
|
|
22
|
+
import React from "react";
|
|
23
23
|
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector.js";
|
|
24
24
|
var streamCache = /* @__PURE__ */ new Map();
|
|
25
25
|
var shapeCache = /* @__PURE__ */ new Map();
|
|
@@ -77,21 +77,23 @@ function useShape(_a) {
|
|
|
77
77
|
]);
|
|
78
78
|
const shapeStream = getShapeStream(options);
|
|
79
79
|
const shape = getShape(shapeStream);
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
80
|
+
const useShapeData = React.useMemo(() => {
|
|
81
|
+
let latestShapeData = parseShapeData(shape);
|
|
82
|
+
const getSnapshot = () => latestShapeData;
|
|
83
|
+
const subscribe = (onStoreChange) => shapeSubscribe(shape, () => {
|
|
84
|
+
latestShapeData = parseShapeData(shape);
|
|
85
|
+
onStoreChange();
|
|
86
|
+
});
|
|
87
|
+
return () => {
|
|
88
|
+
return useSyncExternalStoreWithSelector(
|
|
89
|
+
subscribe,
|
|
90
|
+
getSnapshot,
|
|
91
|
+
getSnapshot,
|
|
92
|
+
selector
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
}, [shape, selector]);
|
|
96
|
+
return useShapeData();
|
|
95
97
|
}
|
|
96
98
|
export {
|
|
97
99
|
getShape,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape<T extends Row = Row>(\n options: ShapeStreamOptions\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n return JSON.stringify(options, Object.keys(options).sort())\n}\n\nexport function getShapeStream<T extends Row = Row>(\n options: ShapeStreamOptions\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return\n if (streamCache.has(shapeHash)) {\n // Return the ShapeStream\n return streamCache.get(shapeHash)! as ShapeStream<T>\n } else {\n const newShapeStream = new ShapeStream<T>(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)! as Shape<T>\n } else {\n const newShape = new Shape<T>(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\nexport interface UseShapeResult<T extends Row = Row> {\n /**\n * The array of rows that make up the Shape.\n * @type {T[]}\n */\n data: T[]\n /**\n * The Shape instance used by this useShape\n * @type {Shape<T>}\n */\n shape: Shape<T>\n error: Shape<T>[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row, Selection>\n extends ShapeStreamOptions {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row = Row,\n Selection = UseShapeResult<SourceData>,\n>({\n selector = identity as (arg: UseShapeResult<SourceData>) => Selection,\n ...options\n}: UseShapeOptions<SourceData, Selection>): Selection {\n const shapeStream = getShapeStream<SourceData>(options as ShapeStreamOptions)\n const shape = getShape<SourceData>(shapeStream)\n\n const useShapeData = React.useMemo(() => {\n let latestShapeData = parseShapeData(shape)\n const getSnapshot = () => latestShapeData\n const subscribe = (onStoreChange: () => void) =>\n shapeSubscribe(shape, () => {\n latestShapeData = parseShapeData(shape)\n onStoreChange()\n })\n\n return () => {\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getSnapshot,\n selector\n )\n }\n }, [shape, selector])\n\n return useShapeData()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,OAAO,WAAW;AAClB,SAAS,wCAAwC;AAEjD,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,eAAsB,aACpB,SACmB;AACnB,QAAM,cAAc,eAAkB,OAAO;AAC7C,QAAM,QAAQ,SAAY,WAAW;AACrC,QAAM,MAAM;AACZ,SAAO;AACT;AAEO,SAAS,kBAAkB,SAAqC;AACrE,SAAO,KAAK,UAAU,SAAS,OAAO,KAAK,OAAO,EAAE,KAAK,CAAC;AAC5D;AAEO,SAAS,eACd,SACgB;AAChB,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,YAAe,OAAO;AAEjD,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAwB,aAAuC;AAE7E,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,MAAS,WAAW;AAEzC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAqBA,SAAS,eAA8B,OAAiB,UAAsB;AAC5E,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAA8B,OAAoC;AACzE,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,SAAS,SAAY,KAAW;AAC9B,SAAO;AACT;AAOO,SAAS,SAGd,IAGoD;AAHpD,eACA;AAAA,eAAW;AAAA,EA5Gb,IA2GE,IAEG,oBAFH,IAEG;AAAA,IADH;AAAA;AAGA,QAAM,cAAc,eAA2B,OAA6B;AAC5E,QAAM,QAAQ,SAAqB,WAAW;AAE9C,QAAM,eAAe,MAAM,QAAQ,MAAM;AACvC,QAAI,kBAAkB,eAAe,KAAK;AAC1C,UAAM,cAAc,MAAM;AAC1B,UAAM,YAAY,CAAC,kBACjB,eAAe,OAAO,MAAM;AAC1B,wBAAkB,eAAe,KAAK;AACtC,oBAAc;AAAA,IAChB,CAAC;AAEH,WAAO,MAAM;AACX,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,CAAC;AAEpB,SAAO,aAAa;AACtB;","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
Shape,
|
|
40
40
|
ShapeStream
|
|
41
41
|
} from "@electric-sql/client";
|
|
42
|
-
import React
|
|
42
|
+
import React from "react";
|
|
43
43
|
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector.js";
|
|
44
44
|
var streamCache = /* @__PURE__ */ new Map();
|
|
45
45
|
var shapeCache = /* @__PURE__ */ new Map();
|
|
@@ -99,21 +99,23 @@ function useShape(_a) {
|
|
|
99
99
|
]);
|
|
100
100
|
const shapeStream = getShapeStream(options);
|
|
101
101
|
const shape = getShape(shapeStream);
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
102
|
+
const useShapeData = React.useMemo(() => {
|
|
103
|
+
let latestShapeData = parseShapeData(shape);
|
|
104
|
+
const getSnapshot = () => latestShapeData;
|
|
105
|
+
const subscribe = (onStoreChange) => shapeSubscribe(shape, () => {
|
|
106
|
+
latestShapeData = parseShapeData(shape);
|
|
107
|
+
onStoreChange();
|
|
108
|
+
});
|
|
109
|
+
return () => {
|
|
110
|
+
return useSyncExternalStoreWithSelector(
|
|
111
|
+
subscribe,
|
|
112
|
+
getSnapshot,
|
|
113
|
+
getSnapshot,
|
|
114
|
+
selector
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
}, [shape, selector]);
|
|
118
|
+
return useShapeData();
|
|
117
119
|
}
|
|
118
120
|
export {
|
|
119
121
|
getShape,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n Row,\n} from '@electric-sql/client'\nimport React from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape<T extends Row = Row>(\n options: ShapeStreamOptions\n): Promise<Shape<T>> {\n const shapeStream = getShapeStream<T>(options)\n const shape = getShape<T>(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n return JSON.stringify(options, Object.keys(options).sort())\n}\n\nexport function getShapeStream<T extends Row = Row>(\n options: ShapeStreamOptions\n): ShapeStream<T> {\n const shapeHash = sortedOptionsHash(options)\n\n // If the stream is already cached, return\n if (streamCache.has(shapeHash)) {\n // Return the ShapeStream\n return streamCache.get(shapeHash)! as ShapeStream<T>\n } else {\n const newShapeStream = new ShapeStream<T>(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)! as Shape<T>\n } else {\n const newShape = new Shape<T>(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\nexport interface UseShapeResult<T extends Row = Row> {\n /**\n * The array of rows that make up the Shape.\n * @type {T[]}\n */\n data: T[]\n /**\n * The Shape instance used by this useShape\n * @type {Shape<T>}\n */\n shape: Shape<T>\n error: Shape<T>[`error`]\n isError: boolean\n /**\n * Has the ShapeStream caught up with the replication log from Postgres.\n */\n isUpToDate: boolean\n}\n\nfunction shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {\n return {\n data: [...shape.valueSync.values()],\n isUpToDate: shape.isUpToDate,\n isError: shape.error !== false,\n shape,\n error: shape.error,\n }\n}\n\nfunction identity<T>(arg: T): T {\n return arg\n}\n\ninterface UseShapeOptions<SourceData extends Row, Selection>\n extends ShapeStreamOptions {\n selector?: (value: UseShapeResult<SourceData>) => Selection\n}\n\nexport function useShape<\n SourceData extends Row = Row,\n Selection = UseShapeResult<SourceData>,\n>({\n selector = identity as (arg: UseShapeResult<SourceData>) => Selection,\n ...options\n}: UseShapeOptions<SourceData, Selection>): Selection {\n const shapeStream = getShapeStream<SourceData>(options as ShapeStreamOptions)\n const shape = getShape<SourceData>(shapeStream)\n\n const useShapeData = React.useMemo(() => {\n let latestShapeData = parseShapeData(shape)\n const getSnapshot = () => latestShapeData\n const subscribe = (onStoreChange: () => void) =>\n shapeSubscribe(shape, () => {\n latestShapeData = parseShapeData(shape)\n onStoreChange()\n })\n\n return () => {\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getSnapshot,\n selector\n )\n }\n }, [shape, selector])\n\n return useShapeData()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,OAAO,WAAW;AAClB,SAAS,wCAAwC;AAEjD,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,aAAa,oBAAI,IAAwB;AAE/C,SAAsB,aACpB,SACmB;AAAA;AACnB,UAAM,cAAc,eAAkB,OAAO;AAC7C,UAAM,QAAQ,SAAY,WAAW;AACrC,UAAM,MAAM;AACZ,WAAO;AAAA,EACT;AAAA;AAEO,SAAS,kBAAkB,SAAqC;AACrE,SAAO,KAAK,UAAU,SAAS,OAAO,KAAK,OAAO,EAAE,KAAK,CAAC;AAC5D;AAEO,SAAS,eACd,SACgB;AAChB,QAAM,YAAY,kBAAkB,OAAO;AAG3C,MAAI,YAAY,IAAI,SAAS,GAAG;AAE9B,WAAO,YAAY,IAAI,SAAS;AAAA,EAClC,OAAO;AACL,UAAM,iBAAiB,IAAI,YAAe,OAAO;AAEjD,gBAAY,IAAI,WAAW,cAAc;AAGzC,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAwB,aAAuC;AAE7E,MAAI,WAAW,IAAI,WAAW,GAAG;AAE/B,WAAO,WAAW,IAAI,WAAW;AAAA,EACnC,OAAO;AACL,UAAM,WAAW,IAAI,MAAS,WAAW;AAEzC,eAAW,IAAI,aAAa,QAAQ;AAGpC,WAAO;AAAA,EACT;AACF;AAqBA,SAAS,eAA8B,OAAiB,UAAsB;AAC5E,QAAM,cAAc,MAAM,UAAU,QAAQ;AAC5C,SAAO,MAAM;AACX,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,eAA8B,OAAoC;AACzE,SAAO;AAAA,IACL,MAAM,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC;AAAA,IAClC,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM,UAAU;AAAA,IACzB;AAAA,IACA,OAAO,MAAM;AAAA,EACf;AACF;AAEA,SAAS,SAAY,KAAW;AAC9B,SAAO;AACT;AAOO,SAAS,SAGd,IAGoD;AAHpD,eACA;AAAA,eAAW;AAAA,EA5Gb,IA2GE,IAEG,oBAFH,IAEG;AAAA,IADH;AAAA;AAGA,QAAM,cAAc,eAA2B,OAA6B;AAC5E,QAAM,QAAQ,SAAqB,WAAW;AAE9C,QAAM,eAAe,MAAM,QAAQ,MAAM;AACvC,QAAI,kBAAkB,eAAe,KAAK;AAC1C,UAAM,cAAc,MAAM;AAC1B,UAAM,YAAY,CAAC,kBACjB,eAAe,OAAO,MAAM;AAC1B,wBAAkB,eAAe,KAAK;AACtC,oBAAc;AAAA,IAChB,CAAC;AAEH,WAAO,MAAM;AACX,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,CAAC;AAEpB,SAAO,aAAa;AACtB;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@electric-sql/react",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "React hooks for ElectricSQL",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cjs/index.cjs",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"homepage": "https://next.electric-sql.com",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"use-sync-external-store": "^1.2.2",
|
|
34
|
-
"@electric-sql/client": "0.3.
|
|
34
|
+
"@electric-sql/client": "0.3.4"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@testing-library/react": "^16.0.0",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"eslint-config-prettier": "^9.1.0",
|
|
47
47
|
"eslint-plugin-prettier": "^5.1.3",
|
|
48
48
|
"glob": "^10.3.10",
|
|
49
|
-
"
|
|
49
|
+
"jsdom": "^25.0.0",
|
|
50
50
|
"pg": "^8.12.0",
|
|
51
51
|
"prettier": "^3.3.2",
|
|
52
52
|
"react": "^18.3.1",
|
package/src/react-hooks.tsx
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
|
-
Value,
|
|
3
2
|
Shape,
|
|
4
3
|
ShapeStream,
|
|
5
4
|
ShapeStreamOptions,
|
|
5
|
+
Row,
|
|
6
6
|
} from '@electric-sql/client'
|
|
7
|
-
import React
|
|
7
|
+
import React from 'react'
|
|
8
8
|
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'
|
|
9
9
|
|
|
10
10
|
const streamCache = new Map<string, ShapeStream>()
|
|
11
11
|
const shapeCache = new Map<ShapeStream, Shape>()
|
|
12
12
|
|
|
13
|
-
export async function preloadShape(
|
|
13
|
+
export async function preloadShape<T extends Row = Row>(
|
|
14
14
|
options: ShapeStreamOptions
|
|
15
|
-
): Promise<Shape
|
|
16
|
-
const shapeStream = getShapeStream(options)
|
|
17
|
-
const shape = getShape(shapeStream)
|
|
15
|
+
): Promise<Shape<T>> {
|
|
16
|
+
const shapeStream = getShapeStream<T>(options)
|
|
17
|
+
const shape = getShape<T>(shapeStream)
|
|
18
18
|
await shape.value
|
|
19
19
|
return shape
|
|
20
20
|
}
|
|
@@ -23,15 +23,17 @@ export function sortedOptionsHash(options: ShapeStreamOptions): string {
|
|
|
23
23
|
return JSON.stringify(options, Object.keys(options).sort())
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export function getShapeStream
|
|
26
|
+
export function getShapeStream<T extends Row = Row>(
|
|
27
|
+
options: ShapeStreamOptions
|
|
28
|
+
): ShapeStream<T> {
|
|
27
29
|
const shapeHash = sortedOptionsHash(options)
|
|
28
30
|
|
|
29
31
|
// If the stream is already cached, return
|
|
30
32
|
if (streamCache.has(shapeHash)) {
|
|
31
33
|
// Return the ShapeStream
|
|
32
|
-
return streamCache.get(shapeHash)!
|
|
34
|
+
return streamCache.get(shapeHash)! as ShapeStream<T>
|
|
33
35
|
} else {
|
|
34
|
-
const newShapeStream = new ShapeStream(options)
|
|
36
|
+
const newShapeStream = new ShapeStream<T>(options)
|
|
35
37
|
|
|
36
38
|
streamCache.set(shapeHash, newShapeStream)
|
|
37
39
|
|
|
@@ -40,13 +42,13 @@ export function getShapeStream(options: ShapeStreamOptions): ShapeStream {
|
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
export function getShape(shapeStream: ShapeStream): Shape {
|
|
45
|
+
export function getShape<T extends Row>(shapeStream: ShapeStream<T>): Shape<T> {
|
|
44
46
|
// If the stream is already cached, return
|
|
45
47
|
if (shapeCache.has(shapeStream)) {
|
|
46
48
|
// Return the ShapeStream
|
|
47
|
-
return shapeCache.get(shapeStream)!
|
|
49
|
+
return shapeCache.get(shapeStream)! as Shape<T>
|
|
48
50
|
} else {
|
|
49
|
-
const newShape = new Shape(shapeStream)
|
|
51
|
+
const newShape = new Shape<T>(shapeStream)
|
|
50
52
|
|
|
51
53
|
shapeCache.set(shapeStream, newShape)
|
|
52
54
|
|
|
@@ -55,18 +57,18 @@ export function getShape(shapeStream: ShapeStream): Shape {
|
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
export interface UseShapeResult {
|
|
60
|
+
export interface UseShapeResult<T extends Row = Row> {
|
|
59
61
|
/**
|
|
60
62
|
* The array of rows that make up the Shape.
|
|
61
|
-
* @type {
|
|
63
|
+
* @type {T[]}
|
|
62
64
|
*/
|
|
63
|
-
data:
|
|
65
|
+
data: T[]
|
|
64
66
|
/**
|
|
65
67
|
* The Shape instance used by this useShape
|
|
66
|
-
* @type
|
|
68
|
+
* @type {Shape<T>}
|
|
67
69
|
*/
|
|
68
|
-
shape: Shape
|
|
69
|
-
error: Shape[`error`]
|
|
70
|
+
shape: Shape<T>
|
|
71
|
+
error: Shape<T>[`error`]
|
|
70
72
|
isError: boolean
|
|
71
73
|
/**
|
|
72
74
|
* Has the ShapeStream caught up with the replication log from Postgres.
|
|
@@ -74,14 +76,14 @@ export interface UseShapeResult {
|
|
|
74
76
|
isUpToDate: boolean
|
|
75
77
|
}
|
|
76
78
|
|
|
77
|
-
function shapeSubscribe(shape: Shape
|
|
79
|
+
function shapeSubscribe<T extends Row>(shape: Shape<T>, callback: () => void) {
|
|
78
80
|
const unsubscribe = shape.subscribe(callback)
|
|
79
81
|
return () => {
|
|
80
82
|
unsubscribe()
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
function parseShapeData(shape: Shape): UseShapeResult {
|
|
86
|
+
function parseShapeData<T extends Row>(shape: Shape<T>): UseShapeResult<T> {
|
|
85
87
|
return {
|
|
86
88
|
data: [...shape.valueSync.values()],
|
|
87
89
|
isUpToDate: shape.isUpToDate,
|
|
@@ -95,32 +97,39 @@ function identity<T>(arg: T): T {
|
|
|
95
97
|
return arg
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
interface UseShapeOptions<
|
|
99
|
-
|
|
100
|
+
interface UseShapeOptions<SourceData extends Row, Selection>
|
|
101
|
+
extends ShapeStreamOptions {
|
|
102
|
+
selector?: (value: UseShapeResult<SourceData>) => Selection
|
|
100
103
|
}
|
|
101
104
|
|
|
102
|
-
export function useShape<
|
|
103
|
-
|
|
105
|
+
export function useShape<
|
|
106
|
+
SourceData extends Row = Row,
|
|
107
|
+
Selection = UseShapeResult<SourceData>,
|
|
108
|
+
>({
|
|
109
|
+
selector = identity as (arg: UseShapeResult<SourceData>) => Selection,
|
|
104
110
|
...options
|
|
105
|
-
}: UseShapeOptions<Selection>): Selection {
|
|
106
|
-
const shapeStream = getShapeStream(options as ShapeStreamOptions)
|
|
107
|
-
const shape = getShape(shapeStream)
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
111
|
+
}: UseShapeOptions<SourceData, Selection>): Selection {
|
|
112
|
+
const shapeStream = getShapeStream<SourceData>(options as ShapeStreamOptions)
|
|
113
|
+
const shape = getShape<SourceData>(shapeStream)
|
|
114
|
+
|
|
115
|
+
const useShapeData = React.useMemo(() => {
|
|
116
|
+
let latestShapeData = parseShapeData(shape)
|
|
117
|
+
const getSnapshot = () => latestShapeData
|
|
118
|
+
const subscribe = (onStoreChange: () => void) =>
|
|
119
|
+
shapeSubscribe(shape, () => {
|
|
120
|
+
latestShapeData = parseShapeData(shape)
|
|
121
|
+
onStoreChange()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
return () => {
|
|
125
|
+
return useSyncExternalStoreWithSelector(
|
|
126
|
+
subscribe,
|
|
127
|
+
getSnapshot,
|
|
128
|
+
getSnapshot,
|
|
129
|
+
selector
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
}, [shape, selector])
|
|
133
|
+
|
|
134
|
+
return useShapeData()
|
|
126
135
|
}
|