@livestore/livestore 0.0.58-dev.1 → 0.0.58-dev.10
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 -117
- package/dist/.tsbuildinfo +1 -1
- package/dist/effect/LiveStore.d.ts +3 -3
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +1 -1
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/global-state.d.ts.map +1 -1
- package/dist/global-state.js +2 -1
- package/dist/global-state.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/reactiveQueries/base-class.d.ts +1 -1
- package/dist/reactiveQueries/base-class.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.js.map +1 -1
- package/dist/reactiveQueries/sql.d.ts +1 -1
- package/dist/reactiveQueries/sql.d.ts.map +1 -1
- package/dist/reactiveQueries/sql.js +4 -4
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/reactiveQueries/sql.test.js +2 -2
- package/dist/reactiveQueries/sql.test.js.map +1 -1
- package/dist/row-query.d.ts +3 -2
- package/dist/row-query.d.ts.map +1 -1
- package/dist/row-query.js +18 -10
- package/dist/row-query.js.map +1 -1
- package/dist/store-devtools.d.ts +2 -2
- package/dist/store-devtools.d.ts.map +1 -1
- package/dist/store-devtools.js +3 -3
- package/dist/store-devtools.js.map +1 -1
- package/dist/store.d.ts +23 -19
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +90 -59
- package/dist/store.js.map +1 -1
- package/dist/utils/dev.d.ts.map +1 -1
- package/dist/utils/dev.js +1 -0
- package/dist/utils/dev.js.map +1 -1
- package/dist/{react/utils → utils}/stack-info.d.ts +1 -2
- package/dist/utils/stack-info.d.ts.map +1 -0
- package/dist/{react/utils → utils}/stack-info.js +1 -9
- package/dist/utils/stack-info.js.map +1 -0
- package/dist/utils/stack-info.test.d.ts.map +1 -0
- package/dist/{__tests__/react/utils → utils}/stack-info.test.js +1 -1
- package/dist/utils/stack-info.test.js.map +1 -0
- package/dist/utils/tests/fixture.d.ts +259 -0
- package/dist/utils/tests/fixture.d.ts.map +1 -0
- package/dist/utils/tests/fixture.js +33 -0
- package/dist/utils/tests/fixture.js.map +1 -0
- package/dist/utils/tests/mod.d.ts +3 -0
- package/dist/utils/tests/mod.d.ts.map +1 -0
- package/dist/utils/tests/mod.js +3 -0
- package/dist/utils/tests/mod.js.map +1 -0
- package/dist/utils/tests/otel.d.ts.map +1 -0
- package/dist/utils/tests/otel.js.map +1 -0
- package/package.json +17 -24
- package/src/ambient.d.ts +3 -0
- package/src/effect/LiveStore.ts +4 -4
- package/src/global-state.ts +5 -1
- package/src/index.ts +17 -4
- package/src/reactiveQueries/base-class.ts +1 -1
- package/src/reactiveQueries/sql.test.ts +2 -2
- package/src/reactiveQueries/sql.ts +5 -5
- package/src/row-query.ts +36 -16
- package/src/store-devtools.ts +5 -5
- package/src/store.ts +146 -78
- package/src/utils/dev.ts +1 -0
- package/src/{__tests__/react/utils → utils}/stack-info.test.ts +1 -1
- package/src/{react/utils → utils}/stack-info.ts +2 -12
- package/src/utils/tests/fixture.ts +77 -0
- package/src/utils/tests/mod.ts +2 -0
- package/tsconfig.json +1 -2
- package/vitest.config.js +0 -8
- package/dist/__tests__/react/fixture.d.ts +0 -461
- package/dist/__tests__/react/fixture.d.ts.map +0 -1
- package/dist/__tests__/react/fixture.js +0 -68
- package/dist/__tests__/react/fixture.js.map +0 -1
- package/dist/__tests__/react/utils/otel.d.ts.map +0 -1
- package/dist/__tests__/react/utils/otel.js.map +0 -1
- package/dist/__tests__/react/utils/stack-info.test.d.ts.map +0 -1
- package/dist/__tests__/react/utils/stack-info.test.js.map +0 -1
- package/dist/react/LiveStoreContext.d.ts +0 -7
- package/dist/react/LiveStoreContext.d.ts.map +0 -1
- package/dist/react/LiveStoreContext.js +0 -13
- package/dist/react/LiveStoreContext.js.map +0 -1
- package/dist/react/LiveStoreProvider.d.ts +0 -47
- package/dist/react/LiveStoreProvider.d.ts.map +0 -1
- package/dist/react/LiveStoreProvider.js +0 -169
- package/dist/react/LiveStoreProvider.js.map +0 -1
- package/dist/react/LiveStoreProvider.test.d.ts +0 -2
- package/dist/react/LiveStoreProvider.test.d.ts.map +0 -1
- package/dist/react/LiveStoreProvider.test.js +0 -62
- package/dist/react/LiveStoreProvider.test.js.map +0 -1
- package/dist/react/components/LiveList.d.ts +0 -21
- package/dist/react/components/LiveList.d.ts.map +0 -1
- package/dist/react/components/LiveList.js +0 -31
- package/dist/react/components/LiveList.js.map +0 -1
- package/dist/react/index.d.ts +0 -11
- package/dist/react/index.d.ts.map +0 -1
- package/dist/react/index.js +0 -10
- package/dist/react/index.js.map +0 -1
- package/dist/react/useAtom.d.ts +0 -10
- package/dist/react/useAtom.d.ts.map +0 -1
- package/dist/react/useAtom.js +0 -37
- package/dist/react/useAtom.js.map +0 -1
- package/dist/react/useLocalId.d.ts +0 -10
- package/dist/react/useLocalId.d.ts.map +0 -1
- package/dist/react/useLocalId.js +0 -21
- package/dist/react/useLocalId.js.map +0 -1
- package/dist/react/useQuery.d.ts +0 -9
- package/dist/react/useQuery.d.ts.map +0 -1
- package/dist/react/useQuery.js +0 -69
- package/dist/react/useQuery.js.map +0 -1
- package/dist/react/useQuery.test.d.ts +0 -2
- package/dist/react/useQuery.test.d.ts.map +0 -1
- package/dist/react/useQuery.test.js +0 -51
- package/dist/react/useQuery.test.js.map +0 -1
- package/dist/react/useRow.d.ts +0 -46
- package/dist/react/useRow.d.ts.map +0 -1
- package/dist/react/useRow.js +0 -94
- package/dist/react/useRow.js.map +0 -1
- package/dist/react/useRow.test.d.ts +0 -2
- package/dist/react/useRow.test.d.ts.map +0 -1
- package/dist/react/useRow.test.js +0 -562
- package/dist/react/useRow.test.js.map +0 -1
- package/dist/react/useTemporaryQuery.d.ts +0 -22
- package/dist/react/useTemporaryQuery.d.ts.map +0 -1
- package/dist/react/useTemporaryQuery.js +0 -70
- package/dist/react/useTemporaryQuery.js.map +0 -1
- package/dist/react/useTemporaryQuery.test.d.ts +0 -2
- package/dist/react/useTemporaryQuery.test.d.ts.map +0 -1
- package/dist/react/useTemporaryQuery.test.js +0 -37
- package/dist/react/useTemporaryQuery.test.js.map +0 -1
- package/dist/react/utils/stack-info.d.ts.map +0 -1
- package/dist/react/utils/stack-info.js.map +0 -1
- package/dist/react/utils/useStateRefWithReactiveInput.d.ts +0 -13
- package/dist/react/utils/useStateRefWithReactiveInput.d.ts.map +0 -1
- package/dist/react/utils/useStateRefWithReactiveInput.js +0 -38
- package/dist/react/utils/useStateRefWithReactiveInput.js.map +0 -1
- package/src/__tests__/react/fixture.tsx +0 -126
- package/src/react/LiveStoreContext.ts +0 -20
- package/src/react/LiveStoreProvider.test.tsx +0 -109
- package/src/react/LiveStoreProvider.tsx +0 -289
- package/src/react/components/LiveList.tsx +0 -84
- package/src/react/index.ts +0 -19
- package/src/react/useAtom.ts +0 -55
- package/src/react/useLocalId.ts +0 -33
- package/src/react/useQuery.test.tsx +0 -82
- package/src/react/useQuery.ts +0 -105
- package/src/react/useRow.test.tsx +0 -699
- package/src/react/useRow.ts +0 -180
- package/src/react/useTemporaryQuery.test.tsx +0 -56
- package/src/react/useTemporaryQuery.ts +0 -121
- package/src/react/utils/useStateRefWithReactiveInput.ts +0 -51
- /package/dist/{__tests__/react/utils → utils}/stack-info.test.d.ts +0 -0
- /package/dist/{__tests__/react/utils → utils/tests}/otel.d.ts +0 -0
- /package/dist/{__tests__/react/utils → utils/tests}/otel.js +0 -0
- /package/src/{__tests__/react/utils → utils/tests}/otel.ts +0 -0
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import * as otel from '@opentelemetry/api';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { useStore } from './LiveStoreContext.js';
|
|
4
|
-
import { useQueryRef } from './useQuery.js';
|
|
5
|
-
// NOTE Given `useMemo` will be called multiple times (e.g. when using React Strict mode or Fast Refresh),
|
|
6
|
-
// we are using this cache to avoid starting multiple queries/spans for the same component.
|
|
7
|
-
// This is somewhat against some recommended React best practices, but it should be fine in our case below.
|
|
8
|
-
// Please definitely open an issue if you see or run into any problems with this approach!
|
|
9
|
-
const cache = new Map();
|
|
10
|
-
/**
|
|
11
|
-
* Creates a query, subscribes and destroys it when the component unmounts.
|
|
12
|
-
*
|
|
13
|
-
* The `key` is used to determine whether the a new query should be created or if the existing one should be reused.
|
|
14
|
-
*/
|
|
15
|
-
export const useTemporaryQuery = (makeQuery, key) => useTemporaryQueryRef(makeQuery, key).current;
|
|
16
|
-
export const useTemporaryQueryRef = (makeQuery, key) => {
|
|
17
|
-
const { query$ } = useMakeTemporaryQuery(makeQuery, key);
|
|
18
|
-
return useQueryRef(query$);
|
|
19
|
-
};
|
|
20
|
-
export const useMakeTemporaryQuery = (makeQuery, key, options) => {
|
|
21
|
-
const { store } = useStore();
|
|
22
|
-
const fullKey = React.useMemo(
|
|
23
|
-
// NOTE We're using the `makeQuery` function body string to make sure the key is unique across the app
|
|
24
|
-
// TODO we should figure out whether this could cause some problems and/or if there's a better way to do this
|
|
25
|
-
() => (Array.isArray(key) ? key.join('-') : key) + '-' + store.reactivityGraph.id + '-' + makeQuery.toString(), [key, makeQuery, store.reactivityGraph.id]);
|
|
26
|
-
const fullKeyRef = React.useRef();
|
|
27
|
-
const { query$, otelContext } = React.useMemo(() => {
|
|
28
|
-
if (fullKeyRef.current !== undefined && fullKeyRef.current !== fullKey) {
|
|
29
|
-
// console.debug('fullKey changed, destroying previous', fullKeyRef.current.split('-')[0]!, fullKey.split('-')[0]!)
|
|
30
|
-
const cachedItem = cache.get(fullKeyRef.current);
|
|
31
|
-
if (cachedItem !== undefined) {
|
|
32
|
-
cachedItem.rc--;
|
|
33
|
-
if (cachedItem.rc === 0) {
|
|
34
|
-
cachedItem.query$.destroy();
|
|
35
|
-
cachedItem.span.end();
|
|
36
|
-
cache.delete(fullKeyRef.current);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
const cachedItem = cache.get(fullKey);
|
|
41
|
-
if (cachedItem !== undefined) {
|
|
42
|
-
cachedItem.rc++;
|
|
43
|
-
return cachedItem;
|
|
44
|
-
}
|
|
45
|
-
const spanName = options?.otel?.spanName ?? `LiveStore:useTemporaryQuery:${key}`;
|
|
46
|
-
const span = store.otel.tracer.startSpan(spanName, { attributes: options?.otel?.attributes }, store.otel.queriesSpanContext);
|
|
47
|
-
const otelContext = otel.trace.setSpan(otel.context.active(), span);
|
|
48
|
-
const query$ = makeQuery(otelContext);
|
|
49
|
-
cache.set(fullKey, { rc: 1, query$, span, otelContext });
|
|
50
|
-
return { query$, otelContext };
|
|
51
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
52
|
-
}, [fullKey]);
|
|
53
|
-
fullKeyRef.current = fullKey;
|
|
54
|
-
React.useEffect(() => {
|
|
55
|
-
return () => {
|
|
56
|
-
const cachedItem = cache.get(fullKey);
|
|
57
|
-
// NOTE in case the fullKey changed then the query was already destroyed in the useMemo above
|
|
58
|
-
if (cachedItem === undefined)
|
|
59
|
-
return;
|
|
60
|
-
cachedItem.rc--;
|
|
61
|
-
if (cachedItem.rc === 0) {
|
|
62
|
-
cachedItem.query$.destroy();
|
|
63
|
-
cachedItem.span.end();
|
|
64
|
-
cache.delete(fullKey);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
}, [fullKey]);
|
|
68
|
-
return { query$, otelContext };
|
|
69
|
-
};
|
|
70
|
-
//# sourceMappingURL=useTemporaryQuery.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTemporaryQuery.js","sourceRoot":"","sources":["../../src/react/useTemporaryQuery.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTemporaryQuery.test.d.ts","sourceRoot":"","sources":["../../src/react/useTemporaryQuery.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { Effect, Schema } from '@livestore/utils/effect';
|
|
2
|
-
import { renderHook } from '@testing-library/react';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
import { makeTodoMvc, tables, todos } from '../__tests__/react/fixture.js';
|
|
5
|
-
import { querySQL } from '../reactiveQueries/sql.js';
|
|
6
|
-
import * as LiveStoreReact from './index.js';
|
|
7
|
-
describe('useTemporaryQuery', () => {
|
|
8
|
-
it('simple', () => Effect.gen(function* () {
|
|
9
|
-
const { wrapper, store, makeRenderCount } = yield* makeTodoMvc();
|
|
10
|
-
const renderCount = makeRenderCount();
|
|
11
|
-
store.mutate(todos.insert({ id: 't1', text: 'buy milk', completed: false }), todos.insert({ id: 't2', text: 'buy bread', completed: false }));
|
|
12
|
-
const queryMap = new Map();
|
|
13
|
-
const { rerender, result, unmount } = renderHook((id) => {
|
|
14
|
-
renderCount.inc();
|
|
15
|
-
return LiveStoreReact.useTemporaryQuery(() => {
|
|
16
|
-
const query$ = querySQL(`select * from todos where id = '${id}'`, {
|
|
17
|
-
schema: Schema.Array(tables.todos.schema),
|
|
18
|
-
});
|
|
19
|
-
queryMap.set(id, query$);
|
|
20
|
-
return query$;
|
|
21
|
-
}, id);
|
|
22
|
-
}, { wrapper, initialProps: 't1' });
|
|
23
|
-
expect(result.current.length).toBe(1);
|
|
24
|
-
expect(result.current[0].text).toBe('buy milk');
|
|
25
|
-
expect(renderCount.val).toBe(1);
|
|
26
|
-
expect(queryMap.get('t1').runs).toBe(1);
|
|
27
|
-
rerender('t2');
|
|
28
|
-
expect(result.current.length).toBe(1);
|
|
29
|
-
expect(result.current[0].text).toBe('buy bread');
|
|
30
|
-
expect(renderCount.val).toBe(2);
|
|
31
|
-
expect(queryMap.get('t1').runs).toBe(1);
|
|
32
|
-
expect(queryMap.get('t2').runs).toBe(1);
|
|
33
|
-
unmount();
|
|
34
|
-
expect(queryMap.get('t2').runs).toBe(1);
|
|
35
|
-
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise));
|
|
36
|
-
});
|
|
37
|
-
//# sourceMappingURL=useTemporaryQuery.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTemporaryQuery.test.js","sourceRoot":"","sources":["../../src/react/useTemporaryQuery.test.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stack-info.d.ts","sourceRoot":"","sources":["../../../src/react/utils/stack-info.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,kBAAkB,QAAwB,CAAA;AAEvD,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,UAAU,EAAE,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAqBD,eAAO,MAAM,8BAA8B,eAAgB,MAAM,KAAG,SAsBnE,CAAA;AAED,eAAO,MAAM,YAAY,QAAO,SAOxB,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stack-info.js","sourceRoot":"","sources":["../../../src/react/utils/stack-info.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC,eAAe,CAAA;AAWvD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,UAAkB,EAAa,EAAE;IAC9E,MAAM,WAAW,GAAG,oBAAoB,CAAA;IACxC,IAAI,KAA6B,CAAA;IACjC,MAAM,MAAM,GAAiB,EAAE,CAAA;IAC/B,IAAI,eAAe,GAAG,KAAK,CAAA;IAE3B,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACvD,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,KAAwC,CAAA;QAEnE,wEAAwE;QACxE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,KAAK,EAAE,CAAC;YACrG,eAAe,GAAG,IAAI,CAAA;YAEtB,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;QACnE,CAAC;aAAM,IAAI,eAAe,EAAE,CAAC;YAC3B,6FAA6F;YAC7F,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;YAClC,MAAK;QACP,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,CAAA;AACnB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,GAAc,EAAE,CAC1C,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;IACjB,KAAK,CAAC,eAAe,GAAG,EAAE,CAAA;IAC1B,iDAAiD;IACjD,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,KAAM,CAAA;IAChC,KAAK,CAAC,eAAe,GAAG,kBAAkB,CAAA;IAC1C,OAAO,8BAA8B,CAAC,KAAK,CAAC,CAAA;AAC9C,CAAC,EAAE,EAAE,CAAC,CAAA"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
/**
|
|
3
|
-
* A variant of `React.useState` which allows the `inputState` to change over time as well.
|
|
4
|
-
* Important: This hook is synchronous / single-render-pass (i.e. doesn't use `useEffect` or `setState` directly).
|
|
5
|
-
*
|
|
6
|
-
* Notes:
|
|
7
|
-
* - The output state is always reset to the input state in case the input state changes (i.e. the previous "external" `setStateAndRerender` call is forgotten)
|
|
8
|
-
* - This hook might not work properly with React Suspense
|
|
9
|
-
* - Also see this Tweet for more potential problems: https://twitter.com/schickling/status/1677317711104278528
|
|
10
|
-
*
|
|
11
|
-
*/
|
|
12
|
-
export declare const useStateRefWithReactiveInput: <T>(inputState: T) => [React.MutableRefObject<T>, (newState: T | ((prev: T) => T)) => void];
|
|
13
|
-
//# sourceMappingURL=useStateRefWithReactiveInput.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useStateRefWithReactiveInput.d.ts","sourceRoot":"","sources":["../../../src/react/utils/useStateRefWithReactiveInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,CAAC,cAChC,CAAC,KACZ,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAwBtE,CAAA"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
/**
|
|
3
|
-
* A variant of `React.useState` which allows the `inputState` to change over time as well.
|
|
4
|
-
* Important: This hook is synchronous / single-render-pass (i.e. doesn't use `useEffect` or `setState` directly).
|
|
5
|
-
*
|
|
6
|
-
* Notes:
|
|
7
|
-
* - The output state is always reset to the input state in case the input state changes (i.e. the previous "external" `setStateAndRerender` call is forgotten)
|
|
8
|
-
* - This hook might not work properly with React Suspense
|
|
9
|
-
* - Also see this Tweet for more potential problems: https://twitter.com/schickling/status/1677317711104278528
|
|
10
|
-
*
|
|
11
|
-
*/
|
|
12
|
-
export const useStateRefWithReactiveInput = (inputState) => {
|
|
13
|
-
const [_, rerender] = React.useState(0);
|
|
14
|
-
const lastKnownInputStateRef = React.useRef(inputState);
|
|
15
|
-
const stateRef = React.useRef(inputState);
|
|
16
|
-
if (lastKnownInputStateRef.current !== inputState) {
|
|
17
|
-
lastKnownInputStateRef.current = inputState;
|
|
18
|
-
// NOTE we don't need to re-render here, because the component is already re-rendering due to the `inputState` change
|
|
19
|
-
stateRef.current = inputState;
|
|
20
|
-
}
|
|
21
|
-
const setStateAndRerender = React.useCallback((newState) => {
|
|
22
|
-
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/37663
|
|
23
|
-
const val = typeof newState === 'function' ? newState(stateRef.current) : newState;
|
|
24
|
-
stateRef.current = val;
|
|
25
|
-
rerender((c) => c + 1);
|
|
26
|
-
}, [rerender]);
|
|
27
|
-
return [stateRef, setStateAndRerender];
|
|
28
|
-
};
|
|
29
|
-
// Down-side of this implementation: Double render pass due to `setState` call (which forces a re-render)
|
|
30
|
-
// Keeping around for now in case `useStateRefWithReactiveInput` doesn't work out
|
|
31
|
-
// const _useStateWithReactiveInput = <T>(inputState: T): [T, (newState: T | ((prev: T) => T)) => void] => {
|
|
32
|
-
// const [externalState, setExternalState] = React.useState(inputState)
|
|
33
|
-
// if (externalState !== inputState) {
|
|
34
|
-
// setExternalState(inputState)
|
|
35
|
-
// }
|
|
36
|
-
// return [externalState, setExternalState]
|
|
37
|
-
// }
|
|
38
|
-
//# sourceMappingURL=useStateRefWithReactiveInput.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useStateRefWithReactiveInput.js","sourceRoot":"","sources":["../../../src/react/utils/useStateRefWithReactiveInput.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,UAAa,EAC0D,EAAE;IACzE,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IAEvC,MAAM,sBAAsB,GAAG,KAAK,CAAC,MAAM,CAAI,UAAU,CAAC,CAAA;IAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAI,UAAU,CAAC,CAAA;IAE5C,IAAI,sBAAsB,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QAClD,sBAAsB,CAAC,OAAO,GAAG,UAAU,CAAA;QAE3C,qHAAqH;QACrH,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAA;IAC/B,CAAC;IAED,MAAM,mBAAmB,GAAG,KAAK,CAAC,WAAW,CAC3C,CAAC,QAA8B,EAAE,EAAE;QACjC,wEAAwE;QACxE,MAAM,GAAG,GAAG,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;QAClF,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAA;QACtB,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACxB,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,OAAO,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;AACxC,CAAC,CAAA;AAED,yGAAyG;AACzG,iFAAiF;AACjF,4GAA4G;AAC5G,yEAAyE;AAEzE,wCAAwC;AACxC,mCAAmC;AACnC,MAAM;AAEN,6CAA6C;AAC7C,IAAI"}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { Effect, FiberSet, Schema as __Schema } from '@livestore/utils/effect'
|
|
2
|
-
import { makeInMemoryAdapter } from '@livestore/web'
|
|
3
|
-
import type * as otel from '@opentelemetry/api'
|
|
4
|
-
import React from 'react'
|
|
5
|
-
|
|
6
|
-
import { globalReactivityGraph } from '../../global-state.js'
|
|
7
|
-
import type { LiveStoreContext } from '../../index.js'
|
|
8
|
-
import { createStore, DbSchema, makeReactivityGraph, makeSchema, sql } from '../../index.js'
|
|
9
|
-
import * as LiveStoreReact from '../../react/index.js'
|
|
10
|
-
|
|
11
|
-
export type Todo = {
|
|
12
|
-
id: string
|
|
13
|
-
text: string
|
|
14
|
-
completed: boolean
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type Filter = 'all' | 'active' | 'completed'
|
|
18
|
-
|
|
19
|
-
export type AppState = {
|
|
20
|
-
newTodoText: string
|
|
21
|
-
filter: Filter
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const todos = DbSchema.table(
|
|
25
|
-
'todos',
|
|
26
|
-
{
|
|
27
|
-
id: DbSchema.text({ primaryKey: true }),
|
|
28
|
-
text: DbSchema.text({ default: '', nullable: false }),
|
|
29
|
-
completed: DbSchema.boolean({ default: false, nullable: false }),
|
|
30
|
-
},
|
|
31
|
-
{ deriveMutations: true, isSingleton: false },
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
export const app = DbSchema.table('app', {
|
|
35
|
-
id: DbSchema.text({ primaryKey: true }),
|
|
36
|
-
newTodoText: DbSchema.text({ default: '', nullable: true }),
|
|
37
|
-
filter: DbSchema.text({ default: 'all', nullable: false }),
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
const userInfo = DbSchema.table(
|
|
41
|
-
'UserInfo',
|
|
42
|
-
{
|
|
43
|
-
username: DbSchema.text({ default: '' }),
|
|
44
|
-
text: DbSchema.text({ default: '' }),
|
|
45
|
-
},
|
|
46
|
-
{ deriveMutations: true },
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
const AppRouterSchema = DbSchema.table(
|
|
50
|
-
'AppRouter',
|
|
51
|
-
{
|
|
52
|
-
currentTaskId: DbSchema.text({ default: null, nullable: true }),
|
|
53
|
-
},
|
|
54
|
-
{ isSingleton: true, deriveMutations: true },
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
export const tables = { todos, app, userInfo, AppRouterSchema }
|
|
58
|
-
export const schema = makeSchema({ tables })
|
|
59
|
-
|
|
60
|
-
export const makeTodoMvc = ({
|
|
61
|
-
otelTracer,
|
|
62
|
-
otelContext,
|
|
63
|
-
useGlobalReactivityGraph = true,
|
|
64
|
-
strictMode = process.env.REACT_STRICT_MODE !== undefined,
|
|
65
|
-
}: {
|
|
66
|
-
otelTracer?: otel.Tracer
|
|
67
|
-
otelContext?: otel.Context
|
|
68
|
-
useGlobalReactivityGraph?: boolean
|
|
69
|
-
strictMode?: boolean
|
|
70
|
-
} = {}) =>
|
|
71
|
-
Effect.gen(function* () {
|
|
72
|
-
const reactivityGraph = useGlobalReactivityGraph ? globalReactivityGraph : makeReactivityGraph()
|
|
73
|
-
|
|
74
|
-
const makeRenderCount = () => {
|
|
75
|
-
let val = 0
|
|
76
|
-
|
|
77
|
-
const inc = () => {
|
|
78
|
-
val += strictMode ? 0.5 : 1
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
get val() {
|
|
83
|
-
return val
|
|
84
|
-
},
|
|
85
|
-
inc,
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const fiberSet = yield* FiberSet.make()
|
|
90
|
-
|
|
91
|
-
const store = yield* createStore({
|
|
92
|
-
schema,
|
|
93
|
-
storeId: 'default',
|
|
94
|
-
boot: (db) => db.execute(sql`INSERT OR IGNORE INTO app (id, newTodoText, filter) VALUES ('static', '', 'all');`),
|
|
95
|
-
adapter: makeInMemoryAdapter(),
|
|
96
|
-
reactivityGraph,
|
|
97
|
-
otelOptions: {
|
|
98
|
-
tracer: otelTracer,
|
|
99
|
-
rootSpanContext: otelContext,
|
|
100
|
-
},
|
|
101
|
-
fiberSet,
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
// TODO improve typing of `LiveStoreContext`
|
|
105
|
-
const storeContext = { stage: 'running', store } as any as LiveStoreContext
|
|
106
|
-
|
|
107
|
-
const MaybeStrictMode = strictMode ? React.StrictMode : React.Fragment
|
|
108
|
-
|
|
109
|
-
const wrapper = ({ children }: any) => (
|
|
110
|
-
<MaybeStrictMode>
|
|
111
|
-
<LiveStoreReact.LiveStoreContext.Provider value={storeContext}>
|
|
112
|
-
{children}
|
|
113
|
-
</LiveStoreReact.LiveStoreContext.Provider>
|
|
114
|
-
</MaybeStrictMode>
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
wrapper,
|
|
119
|
-
AppComponentSchema: userInfo,
|
|
120
|
-
AppRouterSchema,
|
|
121
|
-
store,
|
|
122
|
-
reactivityGraph,
|
|
123
|
-
makeRenderCount,
|
|
124
|
-
strictMode,
|
|
125
|
-
}
|
|
126
|
-
})
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import React, { useContext } from 'react'
|
|
2
|
-
|
|
3
|
-
import type { LiveStoreContextRunning as LiveStoreContext_ } from '../effect/LiveStore.js'
|
|
4
|
-
import type { Store } from '../store.js'
|
|
5
|
-
|
|
6
|
-
export const LiveStoreContext = React.createContext<LiveStoreContext_ | undefined>(undefined)
|
|
7
|
-
|
|
8
|
-
export const useStore = (): { store: Store } => {
|
|
9
|
-
const storeContext = useContext(LiveStoreContext)
|
|
10
|
-
|
|
11
|
-
if (storeContext === undefined) {
|
|
12
|
-
throw new Error(`useStore can only be used inside StoreContext.Provider`)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (storeContext.stage !== 'running') {
|
|
16
|
-
throw new Error(`useStore can only be used after the store is running`)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return storeContext
|
|
20
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import type { BootDb } from '@livestore/common'
|
|
2
|
-
import { sql } from '@livestore/common'
|
|
3
|
-
import { Schema } from '@livestore/utils/effect'
|
|
4
|
-
import { makeInMemoryAdapter } from '@livestore/web'
|
|
5
|
-
import { render, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react'
|
|
6
|
-
import React from 'react'
|
|
7
|
-
import { unstable_batchedUpdates as batchUpdates } from 'react-dom'
|
|
8
|
-
import { describe, expect, it } from 'vitest'
|
|
9
|
-
|
|
10
|
-
import { schema, tables } from '../__tests__/react/fixture.js'
|
|
11
|
-
import { querySQL } from '../reactiveQueries/sql.js'
|
|
12
|
-
import * as LiveStoreReact from './index.js'
|
|
13
|
-
import { LiveStoreProvider } from './LiveStoreProvider.js'
|
|
14
|
-
|
|
15
|
-
describe('LiveStoreProvider', () => {
|
|
16
|
-
it('simple', async () => {
|
|
17
|
-
let appRenderCount = 0
|
|
18
|
-
|
|
19
|
-
const allTodos$ = querySQL(`select * from todos`, { schema: Schema.Array(tables.todos.schema) })
|
|
20
|
-
|
|
21
|
-
const App = () => {
|
|
22
|
-
appRenderCount++
|
|
23
|
-
|
|
24
|
-
const todos = LiveStoreReact.useQuery(allTodos$)
|
|
25
|
-
|
|
26
|
-
return <div>{JSON.stringify(todos)}</div>
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const abortController = new AbortController()
|
|
30
|
-
|
|
31
|
-
const Root = ({ forceUpdate }: { forceUpdate: number }) => {
|
|
32
|
-
const bootCb = React.useCallback(
|
|
33
|
-
(db: BootDb) =>
|
|
34
|
-
db.execute(sql`INSERT OR IGNORE INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0);`),
|
|
35
|
-
[],
|
|
36
|
-
)
|
|
37
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
38
|
-
const adapterMemo = React.useMemo(() => makeInMemoryAdapter(), [forceUpdate])
|
|
39
|
-
return (
|
|
40
|
-
<LiveStoreProvider
|
|
41
|
-
schema={schema}
|
|
42
|
-
renderLoading={(status) => <div>Loading LiveStore: {status.stage}</div>}
|
|
43
|
-
adapter={adapterMemo}
|
|
44
|
-
boot={bootCb}
|
|
45
|
-
signal={abortController.signal}
|
|
46
|
-
batchUpdates={batchUpdates}
|
|
47
|
-
>
|
|
48
|
-
<App />
|
|
49
|
-
</LiveStoreProvider>
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const { rerender } = render(<Root forceUpdate={1} />)
|
|
54
|
-
|
|
55
|
-
expect(appRenderCount).toBe(0)
|
|
56
|
-
|
|
57
|
-
await waitForElementToBeRemoved(() => screen.getByText((_) => _.startsWith('Loading LiveStore')))
|
|
58
|
-
|
|
59
|
-
expect(appRenderCount).toBe(1)
|
|
60
|
-
|
|
61
|
-
rerender(<Root forceUpdate={2} />)
|
|
62
|
-
|
|
63
|
-
await waitFor(() => screen.getByText('Loading LiveStore: loading'))
|
|
64
|
-
await waitFor(() => screen.getByText((_) => _.includes('buy milk')))
|
|
65
|
-
|
|
66
|
-
expect(appRenderCount).toBe(2)
|
|
67
|
-
|
|
68
|
-
abortController.abort()
|
|
69
|
-
|
|
70
|
-
await waitFor(() => screen.getByText('LiveStore Shutdown due to abort signal'))
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('error during boot', async () => {
|
|
74
|
-
let appRenderCount = 0
|
|
75
|
-
|
|
76
|
-
const App = () => {
|
|
77
|
-
appRenderCount++
|
|
78
|
-
|
|
79
|
-
return <div>hello world</div>
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const Root = ({ forceUpdate }: { forceUpdate: number }) => {
|
|
83
|
-
const bootCb = React.useCallback(
|
|
84
|
-
(db: BootDb) =>
|
|
85
|
-
db.execute(sql`INSERT INTO todos_mising_table (id, text, completed) VALUES ('t1', 'buy milk', 0);`),
|
|
86
|
-
[],
|
|
87
|
-
)
|
|
88
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
89
|
-
const adapterMemo = React.useMemo(() => makeInMemoryAdapter(), [forceUpdate])
|
|
90
|
-
return (
|
|
91
|
-
<LiveStoreProvider
|
|
92
|
-
schema={schema}
|
|
93
|
-
renderLoading={(status) => <div>Loading LiveStore: {status.stage}</div>}
|
|
94
|
-
adapter={adapterMemo}
|
|
95
|
-
boot={bootCb}
|
|
96
|
-
batchUpdates={batchUpdates}
|
|
97
|
-
>
|
|
98
|
-
<App />
|
|
99
|
-
</LiveStoreProvider>
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
render(<Root forceUpdate={1} />)
|
|
104
|
-
|
|
105
|
-
expect(appRenderCount).toBe(0)
|
|
106
|
-
|
|
107
|
-
await waitFor(() => screen.getByText((_) => _.startsWith('LiveStore.UnexpectedError')))
|
|
108
|
-
})
|
|
109
|
-
})
|