@electric-sql/react 0.0.7 → 0.0.8

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/package.json CHANGED
@@ -1,12 +1,24 @@
1
1
  {
2
2
  "name": "@electric-sql/react",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "React hooks for ElectricSQL",
5
- "main": "dist/index.js",
5
+ "type": "module",
6
+ "main": "dist/cjs/index.cjs",
7
+ "module": "dist/index.legacy-esm.js",
6
8
  "types": "dist/index.d.ts",
9
+ "exports": {
10
+ "./package.json": "./package.json",
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.mjs",
14
+ "default": "./dist/cjs/index.cjs"
15
+ }
16
+ },
7
17
  "files": [
8
- "dist"
18
+ "dist",
19
+ "src"
9
20
  ],
21
+ "sideEffects": false,
10
22
  "repository": {
11
23
  "type": "git",
12
24
  "url": "git+https://github.com/electric-sql/electric-next.git"
@@ -19,7 +31,7 @@
19
31
  "homepage": "https://next.electric-sql.com",
20
32
  "dependencies": {
21
33
  "use-sync-external-store": "^1.2.2",
22
- "@electric-sql/next": "0.0.7"
34
+ "@electric-sql/next": "0.0.8"
23
35
  },
24
36
  "devDependencies": {
25
37
  "@testing-library/react": "^16.0.0",
@@ -52,9 +64,6 @@
52
64
  "optional": true
53
65
  }
54
66
  },
55
- "exports": {
56
- ".": "./dist/index.js"
57
- },
58
67
  "typesVersions": {
59
68
  "*": {
60
69
  "*": [
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './react-hooks'
@@ -0,0 +1,167 @@
1
+ import {
2
+ JsonSerializable,
3
+ Shape,
4
+ ShapeStream,
5
+ ShapeStreamOptions,
6
+ } from '@electric-sql/next'
7
+ import React, { createContext, useCallback, useContext, useRef } from 'react'
8
+ import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector'
9
+
10
+ interface ShapeContextType {
11
+ getShape: (shapeStream: ShapeStream) => Shape
12
+ getShapeStream: (options: ShapeStreamOptions) => ShapeStream
13
+ }
14
+
15
+ // Create a Context
16
+ const ShapesContext = createContext<ShapeContextType | null>(null)
17
+
18
+ const streamCache = new Map<string, ShapeStream>()
19
+ const shapeCache = new Map<ShapeStream, Shape>()
20
+
21
+ export async function preloadShape(
22
+ options: ShapeStreamOptions
23
+ ): Promise<Shape> {
24
+ const shapeStream = getShapeStream(options)
25
+ const shape = getShape(shapeStream)
26
+ await shape.value
27
+ return shape
28
+ }
29
+
30
+ export function sortedOptionsHash(options: ShapeStreamOptions): string {
31
+ const shapeDef = JSON.stringify(
32
+ options.shape,
33
+ Object.keys(options.shape).sort()
34
+ )
35
+ // eslint-disable-next-line
36
+ const { shape, ...optionsWithoutShapeDef } = options
37
+ const allOptions = JSON.stringify(
38
+ optionsWithoutShapeDef,
39
+ Object.keys(options).sort()
40
+ )
41
+ const shapeHash = shapeDef + allOptions
42
+
43
+ return shapeHash
44
+ }
45
+
46
+ export function getShapeStream(options: ShapeStreamOptions): ShapeStream {
47
+ const shapeHash = sortedOptionsHash(options)
48
+
49
+ // If the stream is already cached, return
50
+ if (streamCache.has(shapeHash)) {
51
+ // Return the ShapeStream
52
+ return streamCache.get(shapeHash)!
53
+ } else {
54
+ const newShapeStream = new ShapeStream(options)
55
+
56
+ streamCache.set(shapeHash, newShapeStream)
57
+
58
+ // Return the created shape
59
+ return newShapeStream
60
+ }
61
+ }
62
+
63
+ export function getShape(shapeStream: ShapeStream): Shape {
64
+ // If the stream is already cached, return
65
+ if (shapeCache.has(shapeStream)) {
66
+ // Return the ShapeStream
67
+ return shapeCache.get(shapeStream)!
68
+ } else {
69
+ const newShape = new Shape(shapeStream)
70
+
71
+ shapeCache.set(shapeStream, newShape)
72
+
73
+ // Return the created shape
74
+ return newShape
75
+ }
76
+ }
77
+
78
+ interface ShapeProviderProps {
79
+ children: React.ReactNode
80
+ }
81
+
82
+ // Shapes Provider Component
83
+ export function ShapesProvider({ children }: ShapeProviderProps): JSX.Element {
84
+ // Provide the context value
85
+ return (
86
+ <ShapesContext.Provider value={{ getShape, getShapeStream }}>
87
+ {children}
88
+ </ShapesContext.Provider>
89
+ )
90
+ }
91
+
92
+ export function useShapeContext() {
93
+ const context = useContext(ShapesContext)
94
+ if (!context) {
95
+ throw new Error(`useShapeContext must be used within a ShapeProvider`)
96
+ }
97
+ return context
98
+ }
99
+
100
+ interface UseShapeResult {
101
+ /**
102
+ * The array of rows that make up the Shape.
103
+ * @type {{ [key: string]: JsonSerializable }[]}
104
+ */
105
+ data: { [key: string]: JsonSerializable }[]
106
+ /**
107
+ * The Shape instance used by this useShape
108
+ * @type(Shape)
109
+ */
110
+ shape: Shape
111
+ error: Shape[`error`]
112
+ isError: boolean
113
+ /**
114
+ * Has the ShapeStream caught up with the replication log from Postgres.
115
+ */
116
+ isUpToDate: boolean
117
+ }
118
+
119
+ function shapeSubscribe(shape: Shape, callback: () => void) {
120
+ const unsubscribe = shape.subscribe(callback)
121
+ return () => {
122
+ unsubscribe()
123
+ }
124
+ }
125
+
126
+ function parseShapeData(shape: Shape): UseShapeResult {
127
+ return {
128
+ data: [...shape.valueSync.values()],
129
+ isUpToDate: shape.isUpToDate,
130
+ isError: shape.error !== false,
131
+ shape,
132
+ error: shape.error,
133
+ }
134
+ }
135
+
136
+ const identity = (arg: unknown) => arg
137
+
138
+ interface UseShapeOptions<Selection> extends ShapeStreamOptions {
139
+ selector?: (value: UseShapeResult) => Selection
140
+ }
141
+
142
+ export function useShape<Selection = UseShapeResult>({
143
+ selector = identity as never,
144
+ ...options
145
+ }: UseShapeOptions<Selection>): Selection {
146
+ const { getShape, getShapeStream } = useShapeContext()
147
+ const shapeStream = getShapeStream(options as ShapeStreamOptions)
148
+ const shape = getShape(shapeStream)
149
+
150
+ const latestShapeData = useRef(parseShapeData(shape))
151
+ const getSnapshot = React.useCallback(() => latestShapeData.current, [])
152
+ const shapeData = useSyncExternalStoreWithSelector(
153
+ useCallback(
154
+ (onStoreChange) =>
155
+ shapeSubscribe(shape, () => {
156
+ latestShapeData.current = parseShapeData(shape)
157
+ onStoreChange()
158
+ }),
159
+ [shape]
160
+ ),
161
+ getSnapshot,
162
+ getSnapshot,
163
+ selector
164
+ )
165
+
166
+ return shapeData
167
+ }
package/dist/index.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from './react-hooks';
package/dist/index.js DELETED
@@ -1 +0,0 @@
1
- export * from './react-hooks';
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './react-hooks'\n"],"mappings":"AAAA,cAAc;","names":[]}
@@ -1,40 +0,0 @@
1
- import { JsonSerializable, Shape, ShapeStream, ShapeStreamOptions } from '@electric-sql/next';
2
- import React from 'react';
3
- interface ShapeContextType {
4
- getShape: (shapeStream: ShapeStream) => Shape;
5
- getShapeStream: (options: ShapeStreamOptions) => ShapeStream;
6
- }
7
- export declare function preloadShape(options: ShapeStreamOptions): Promise<Shape>;
8
- export declare function sortedOptionsHash(options: ShapeStreamOptions): string;
9
- export declare function getShapeStream(options: ShapeStreamOptions): ShapeStream;
10
- export declare function getShape(shapeStream: ShapeStream): Shape;
11
- interface ShapeProviderProps {
12
- children: React.ReactNode;
13
- }
14
- export declare function ShapesProvider({ children }: ShapeProviderProps): JSX.Element;
15
- export declare function useShapeContext(): ShapeContextType;
16
- interface UseShapeResult {
17
- /**
18
- * The array of rows that make up the Shape.
19
- * @type {{ [key: string]: JsonSerializable }[]}
20
- */
21
- data: {
22
- [key: string]: JsonSerializable;
23
- }[];
24
- /**
25
- * The Shape instance used by this useShape
26
- * @type(Shape)
27
- */
28
- shape: Shape;
29
- error: Shape[`error`];
30
- isError: boolean;
31
- /**
32
- * Has the ShapeStream caught up with the replication log from Postgres.
33
- */
34
- isUpToDate: boolean;
35
- }
36
- interface UseShapeOptions<Selection> extends ShapeStreamOptions {
37
- selector?: (value: UseShapeResult) => Selection;
38
- }
39
- export declare function useShape<Selection = UseShapeResult>({ selector, ...options }: UseShapeOptions<Selection>): Selection;
40
- export {};
@@ -1,145 +0,0 @@
1
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
2
- var __hasOwnProp = Object.prototype.hasOwnProperty;
3
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
4
- var __objRest = (source, exclude) => {
5
- var target = {};
6
- for (var prop in source)
7
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
8
- target[prop] = source[prop];
9
- if (source != null && __getOwnPropSymbols)
10
- for (var prop of __getOwnPropSymbols(source)) {
11
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
12
- target[prop] = source[prop];
13
- }
14
- return target;
15
- };
16
- var __async = (__this, __arguments, generator) => {
17
- return new Promise((resolve, reject) => {
18
- var fulfilled = (value) => {
19
- try {
20
- step(generator.next(value));
21
- } catch (e) {
22
- reject(e);
23
- }
24
- };
25
- var rejected = (value) => {
26
- try {
27
- step(generator.throw(value));
28
- } catch (e) {
29
- reject(e);
30
- }
31
- };
32
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
33
- step((generator = generator.apply(__this, __arguments)).next());
34
- });
35
- };
36
- import {
37
- Shape,
38
- ShapeStream
39
- } from "@electric-sql/next";
40
- import React, { createContext, useCallback, useContext, useRef } from "react";
41
- import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector";
42
- const ShapesContext = createContext(null);
43
- const streamCache = /* @__PURE__ */ new Map();
44
- const shapeCache = /* @__PURE__ */ new Map();
45
- function preloadShape(options) {
46
- return __async(this, null, function* () {
47
- const shapeStream = getShapeStream(options);
48
- const shape = getShape(shapeStream);
49
- yield shape.value;
50
- return shape;
51
- });
52
- }
53
- function sortedOptionsHash(options) {
54
- const shapeDef = JSON.stringify(
55
- options.shape,
56
- Object.keys(options.shape).sort()
57
- );
58
- const _a = options, { shape } = _a, optionsWithoutShapeDef = __objRest(_a, ["shape"]);
59
- const allOptions = JSON.stringify(
60
- optionsWithoutShapeDef,
61
- Object.keys(options).sort()
62
- );
63
- const shapeHash = shapeDef + allOptions;
64
- return shapeHash;
65
- }
66
- function getShapeStream(options) {
67
- const shapeHash = sortedOptionsHash(options);
68
- if (streamCache.has(shapeHash)) {
69
- return streamCache.get(shapeHash);
70
- } else {
71
- const newShapeStream = new ShapeStream(options);
72
- streamCache.set(shapeHash, newShapeStream);
73
- return newShapeStream;
74
- }
75
- }
76
- function getShape(shapeStream) {
77
- if (shapeCache.has(shapeStream)) {
78
- return shapeCache.get(shapeStream);
79
- } else {
80
- const newShape = new Shape(shapeStream);
81
- shapeCache.set(shapeStream, newShape);
82
- return newShape;
83
- }
84
- }
85
- function ShapesProvider({ children }) {
86
- return /* @__PURE__ */ React.createElement(ShapesContext.Provider, { value: { getShape, getShapeStream } }, children);
87
- }
88
- function useShapeContext() {
89
- const context = useContext(ShapesContext);
90
- if (!context) {
91
- throw new Error(`useShapeContext must be used within a ShapeProvider`);
92
- }
93
- return context;
94
- }
95
- function shapeSubscribe(shape, callback) {
96
- const unsubscribe = shape.subscribe(callback);
97
- return () => {
98
- unsubscribe();
99
- };
100
- }
101
- function parseShapeData(shape) {
102
- return {
103
- data: [...shape.valueSync.values()],
104
- isUpToDate: shape.isUpToDate,
105
- isError: shape.error !== false,
106
- shape,
107
- error: shape.error
108
- };
109
- }
110
- const identity = (arg) => arg;
111
- function useShape(_a) {
112
- var _b = _a, {
113
- selector = identity
114
- } = _b, options = __objRest(_b, [
115
- "selector"
116
- ]);
117
- const { getShape: getShape2, getShapeStream: getShapeStream2 } = useShapeContext();
118
- const shapeStream = getShapeStream2(options);
119
- const shape = getShape2(shapeStream);
120
- const latestShapeData = useRef(parseShapeData(shape));
121
- const getSnapshot = React.useCallback(() => latestShapeData.current, []);
122
- const shapeData = useSyncExternalStoreWithSelector(
123
- useCallback(
124
- (onStoreChange) => shapeSubscribe(shape, () => {
125
- latestShapeData.current = parseShapeData(shape);
126
- onStoreChange();
127
- }),
128
- [shape]
129
- ),
130
- getSnapshot,
131
- getSnapshot,
132
- selector
133
- );
134
- return shapeData;
135
- }
136
- export {
137
- ShapesProvider,
138
- getShape,
139
- getShapeStream,
140
- preloadShape,
141
- sortedOptionsHash,
142
- useShape,
143
- useShapeContext
144
- };
145
- //# sourceMappingURL=react-hooks.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/react-hooks.tsx"],"sourcesContent":["import {\n JsonSerializable,\n Shape,\n ShapeStream,\n ShapeStreamOptions,\n} from '@electric-sql/next'\nimport React, { createContext, useCallback, useContext, useRef } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector'\n\ninterface ShapeContextType {\n getShape: (shapeStream: ShapeStream) => Shape\n getShapeStream: (options: ShapeStreamOptions) => ShapeStream\n}\n\n// Create a Context\nconst ShapesContext = createContext<ShapeContextType | null>(null)\n\nconst streamCache = new Map<string, ShapeStream>()\nconst shapeCache = new Map<ShapeStream, Shape>()\n\nexport async function preloadShape(\n options: ShapeStreamOptions\n): Promise<Shape> {\n const shapeStream = getShapeStream(options)\n const shape = getShape(shapeStream)\n await shape.value\n return shape\n}\n\nexport function sortedOptionsHash(options: ShapeStreamOptions): string {\n const shapeDef = JSON.stringify(\n options.shape,\n Object.keys(options.shape).sort()\n )\n // eslint-disable-next-line\n const { shape, ...optionsWithoutShapeDef } = options\n const allOptions = JSON.stringify(\n optionsWithoutShapeDef,\n Object.keys(options).sort()\n )\n const shapeHash = shapeDef + allOptions\n\n return shapeHash\n}\n\nexport function getShapeStream(options: ShapeStreamOptions): ShapeStream {\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)!\n } else {\n const newShapeStream = new ShapeStream(options)\n\n streamCache.set(shapeHash, newShapeStream)\n\n // Return the created shape\n return newShapeStream\n }\n}\n\nexport function getShape(shapeStream: ShapeStream): Shape {\n // If the stream is already cached, return\n if (shapeCache.has(shapeStream)) {\n // Return the ShapeStream\n return shapeCache.get(shapeStream)!\n } else {\n const newShape = new Shape(shapeStream)\n\n shapeCache.set(shapeStream, newShape)\n\n // Return the created shape\n return newShape\n }\n}\n\ninterface ShapeProviderProps {\n children: React.ReactNode\n}\n\n// Shapes Provider Component\nexport function ShapesProvider({ children }: ShapeProviderProps): JSX.Element {\n // Provide the context value\n return (\n <ShapesContext.Provider value={{ getShape, getShapeStream }}>\n {children}\n </ShapesContext.Provider>\n )\n}\n\nexport function useShapeContext() {\n const context = useContext(ShapesContext)\n if (!context) {\n throw new Error(`useShapeContext must be used within a ShapeProvider`)\n }\n return context\n}\n\ninterface UseShapeResult {\n /**\n * The array of rows that make up the Shape.\n * @type {{ [key: string]: JsonSerializable }[]}\n */\n data: { [key: string]: JsonSerializable }[]\n /**\n * The Shape instance used by this useShape\n * @type(Shape)\n */\n shape: Shape\n error: Shape[`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(shape: Shape, callback: () => void) {\n const unsubscribe = shape.subscribe(callback)\n return () => {\n unsubscribe()\n }\n}\n\nfunction parseShapeData(shape: Shape): UseShapeResult {\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\nconst identity = (arg: unknown) => arg\n\ninterface UseShapeOptions<Selection> extends ShapeStreamOptions {\n selector?: (value: UseShapeResult) => Selection\n}\n\nexport function useShape<Selection = UseShapeResult>({\n selector = identity as never,\n ...options\n}: UseShapeOptions<Selection>): Selection {\n const { getShape, getShapeStream } = useShapeContext()\n const shapeStream = getShapeStream(options as ShapeStreamOptions)\n const shape = getShape(shapeStream)\n\n const latestShapeData = useRef(parseShapeData(shape))\n const getSnapshot = React.useCallback(() => latestShapeData.current, [])\n const shapeData = useSyncExternalStoreWithSelector(\n useCallback(\n (onStoreChange) =>\n shapeSubscribe(shape, () => {\n latestShapeData.current = parseShapeData(shape)\n onStoreChange()\n }),\n [shape]\n ),\n getSnapshot,\n getSnapshot,\n selector\n )\n\n return shapeData\n}\n"],"mappings":"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","names":["getShape","getShapeStream"]}
@@ -1,113 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __rest = (this && this.__rest) || function (s, e) {
11
- var t = {};
12
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13
- t[p] = s[p];
14
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
15
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17
- t[p[i]] = s[p[i]];
18
- }
19
- return t;
20
- };
21
- import { Shape, ShapeStream, } from '@electric-sql/next';
22
- import React, { createContext, useCallback, useContext, useRef } from 'react';
23
- import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector';
24
- // Create a Context
25
- const ShapesContext = createContext(null);
26
- const streamCache = new Map();
27
- const shapeCache = new Map();
28
- export function preloadShape(options) {
29
- return __awaiter(this, void 0, void 0, function* () {
30
- const shapeStream = getShapeStream(options);
31
- const shape = getShape(shapeStream);
32
- yield shape.value;
33
- return shape;
34
- });
35
- }
36
- export function sortedOptionsHash(options) {
37
- const shapeDef = JSON.stringify(options.shape, Object.keys(options.shape).sort());
38
- // eslint-disable-next-line
39
- const { shape } = options, optionsWithoutShapeDef = __rest(options, ["shape"]);
40
- const allOptions = JSON.stringify(optionsWithoutShapeDef, Object.keys(options).sort());
41
- const shapeHash = shapeDef + allOptions;
42
- return shapeHash;
43
- }
44
- export function getShapeStream(options) {
45
- const shapeHash = sortedOptionsHash(options);
46
- // If the stream is already cached, return
47
- if (streamCache.has(shapeHash)) {
48
- // Return the ShapeStream
49
- return streamCache.get(shapeHash);
50
- }
51
- else {
52
- const newShapeStream = new ShapeStream(options);
53
- streamCache.set(shapeHash, newShapeStream);
54
- // Return the created shape
55
- return newShapeStream;
56
- }
57
- }
58
- export function getShape(shapeStream) {
59
- // If the stream is already cached, return
60
- if (shapeCache.has(shapeStream)) {
61
- // Return the ShapeStream
62
- return shapeCache.get(shapeStream);
63
- }
64
- else {
65
- const newShape = new Shape(shapeStream);
66
- shapeCache.set(shapeStream, newShape);
67
- // Return the created shape
68
- return newShape;
69
- }
70
- }
71
- // Shapes Provider Component
72
- export function ShapesProvider({ children }) {
73
- // Provide the context value
74
- return (<ShapesContext.Provider value={{ getShape, getShapeStream }}>
75
- {children}
76
- </ShapesContext.Provider>);
77
- }
78
- export function useShapeContext() {
79
- const context = useContext(ShapesContext);
80
- if (!context) {
81
- throw new Error(`useShapeContext must be used within a ShapeProvider`);
82
- }
83
- return context;
84
- }
85
- function shapeSubscribe(shape, callback) {
86
- const unsubscribe = shape.subscribe(callback);
87
- return () => {
88
- unsubscribe();
89
- };
90
- }
91
- function parseShapeData(shape) {
92
- return {
93
- data: [...shape.valueSync.values()],
94
- isUpToDate: shape.isUpToDate,
95
- isError: shape.error !== false,
96
- shape,
97
- error: shape.error,
98
- };
99
- }
100
- const identity = (arg) => arg;
101
- export function useShape(_a) {
102
- var { selector = identity } = _a, options = __rest(_a, ["selector"]);
103
- const { getShape, getShapeStream } = useShapeContext();
104
- const shapeStream = getShapeStream(options);
105
- const shape = getShape(shapeStream);
106
- const latestShapeData = useRef(parseShapeData(shape));
107
- const getSnapshot = React.useCallback(() => latestShapeData.current, []);
108
- const shapeData = useSyncExternalStoreWithSelector(useCallback((onStoreChange) => shapeSubscribe(shape, () => {
109
- latestShapeData.current = parseShapeData(shape);
110
- onStoreChange();
111
- }), [shape]), getSnapshot, getSnapshot, selector);
112
- return shapeData;
113
- }