@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.
Files changed (157) hide show
  1. package/README.md +1 -117
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/effect/LiveStore.d.ts +3 -3
  4. package/dist/effect/LiveStore.d.ts.map +1 -1
  5. package/dist/effect/LiveStore.js +1 -1
  6. package/dist/effect/LiveStore.js.map +1 -1
  7. package/dist/global-state.d.ts.map +1 -1
  8. package/dist/global-state.js +2 -1
  9. package/dist/global-state.js.map +1 -1
  10. package/dist/index.d.ts +8 -6
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +4 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/reactiveQueries/base-class.d.ts +1 -1
  15. package/dist/reactiveQueries/base-class.d.ts.map +1 -1
  16. package/dist/reactiveQueries/base-class.js.map +1 -1
  17. package/dist/reactiveQueries/sql.d.ts +1 -1
  18. package/dist/reactiveQueries/sql.d.ts.map +1 -1
  19. package/dist/reactiveQueries/sql.js +4 -4
  20. package/dist/reactiveQueries/sql.js.map +1 -1
  21. package/dist/reactiveQueries/sql.test.js +2 -2
  22. package/dist/reactiveQueries/sql.test.js.map +1 -1
  23. package/dist/row-query.d.ts +3 -2
  24. package/dist/row-query.d.ts.map +1 -1
  25. package/dist/row-query.js +18 -10
  26. package/dist/row-query.js.map +1 -1
  27. package/dist/store-devtools.d.ts +2 -2
  28. package/dist/store-devtools.d.ts.map +1 -1
  29. package/dist/store-devtools.js +3 -3
  30. package/dist/store-devtools.js.map +1 -1
  31. package/dist/store.d.ts +23 -19
  32. package/dist/store.d.ts.map +1 -1
  33. package/dist/store.js +90 -59
  34. package/dist/store.js.map +1 -1
  35. package/dist/utils/dev.d.ts.map +1 -1
  36. package/dist/utils/dev.js +1 -0
  37. package/dist/utils/dev.js.map +1 -1
  38. package/dist/{react/utils → utils}/stack-info.d.ts +1 -2
  39. package/dist/utils/stack-info.d.ts.map +1 -0
  40. package/dist/{react/utils → utils}/stack-info.js +1 -9
  41. package/dist/utils/stack-info.js.map +1 -0
  42. package/dist/utils/stack-info.test.d.ts.map +1 -0
  43. package/dist/{__tests__/react/utils → utils}/stack-info.test.js +1 -1
  44. package/dist/utils/stack-info.test.js.map +1 -0
  45. package/dist/utils/tests/fixture.d.ts +259 -0
  46. package/dist/utils/tests/fixture.d.ts.map +1 -0
  47. package/dist/utils/tests/fixture.js +33 -0
  48. package/dist/utils/tests/fixture.js.map +1 -0
  49. package/dist/utils/tests/mod.d.ts +3 -0
  50. package/dist/utils/tests/mod.d.ts.map +1 -0
  51. package/dist/utils/tests/mod.js +3 -0
  52. package/dist/utils/tests/mod.js.map +1 -0
  53. package/dist/utils/tests/otel.d.ts.map +1 -0
  54. package/dist/utils/tests/otel.js.map +1 -0
  55. package/package.json +17 -24
  56. package/src/ambient.d.ts +3 -0
  57. package/src/effect/LiveStore.ts +4 -4
  58. package/src/global-state.ts +5 -1
  59. package/src/index.ts +17 -4
  60. package/src/reactiveQueries/base-class.ts +1 -1
  61. package/src/reactiveQueries/sql.test.ts +2 -2
  62. package/src/reactiveQueries/sql.ts +5 -5
  63. package/src/row-query.ts +36 -16
  64. package/src/store-devtools.ts +5 -5
  65. package/src/store.ts +146 -78
  66. package/src/utils/dev.ts +1 -0
  67. package/src/{__tests__/react/utils → utils}/stack-info.test.ts +1 -1
  68. package/src/{react/utils → utils}/stack-info.ts +2 -12
  69. package/src/utils/tests/fixture.ts +77 -0
  70. package/src/utils/tests/mod.ts +2 -0
  71. package/tsconfig.json +1 -2
  72. package/vitest.config.js +0 -8
  73. package/dist/__tests__/react/fixture.d.ts +0 -461
  74. package/dist/__tests__/react/fixture.d.ts.map +0 -1
  75. package/dist/__tests__/react/fixture.js +0 -68
  76. package/dist/__tests__/react/fixture.js.map +0 -1
  77. package/dist/__tests__/react/utils/otel.d.ts.map +0 -1
  78. package/dist/__tests__/react/utils/otel.js.map +0 -1
  79. package/dist/__tests__/react/utils/stack-info.test.d.ts.map +0 -1
  80. package/dist/__tests__/react/utils/stack-info.test.js.map +0 -1
  81. package/dist/react/LiveStoreContext.d.ts +0 -7
  82. package/dist/react/LiveStoreContext.d.ts.map +0 -1
  83. package/dist/react/LiveStoreContext.js +0 -13
  84. package/dist/react/LiveStoreContext.js.map +0 -1
  85. package/dist/react/LiveStoreProvider.d.ts +0 -47
  86. package/dist/react/LiveStoreProvider.d.ts.map +0 -1
  87. package/dist/react/LiveStoreProvider.js +0 -169
  88. package/dist/react/LiveStoreProvider.js.map +0 -1
  89. package/dist/react/LiveStoreProvider.test.d.ts +0 -2
  90. package/dist/react/LiveStoreProvider.test.d.ts.map +0 -1
  91. package/dist/react/LiveStoreProvider.test.js +0 -62
  92. package/dist/react/LiveStoreProvider.test.js.map +0 -1
  93. package/dist/react/components/LiveList.d.ts +0 -21
  94. package/dist/react/components/LiveList.d.ts.map +0 -1
  95. package/dist/react/components/LiveList.js +0 -31
  96. package/dist/react/components/LiveList.js.map +0 -1
  97. package/dist/react/index.d.ts +0 -11
  98. package/dist/react/index.d.ts.map +0 -1
  99. package/dist/react/index.js +0 -10
  100. package/dist/react/index.js.map +0 -1
  101. package/dist/react/useAtom.d.ts +0 -10
  102. package/dist/react/useAtom.d.ts.map +0 -1
  103. package/dist/react/useAtom.js +0 -37
  104. package/dist/react/useAtom.js.map +0 -1
  105. package/dist/react/useLocalId.d.ts +0 -10
  106. package/dist/react/useLocalId.d.ts.map +0 -1
  107. package/dist/react/useLocalId.js +0 -21
  108. package/dist/react/useLocalId.js.map +0 -1
  109. package/dist/react/useQuery.d.ts +0 -9
  110. package/dist/react/useQuery.d.ts.map +0 -1
  111. package/dist/react/useQuery.js +0 -69
  112. package/dist/react/useQuery.js.map +0 -1
  113. package/dist/react/useQuery.test.d.ts +0 -2
  114. package/dist/react/useQuery.test.d.ts.map +0 -1
  115. package/dist/react/useQuery.test.js +0 -51
  116. package/dist/react/useQuery.test.js.map +0 -1
  117. package/dist/react/useRow.d.ts +0 -46
  118. package/dist/react/useRow.d.ts.map +0 -1
  119. package/dist/react/useRow.js +0 -94
  120. package/dist/react/useRow.js.map +0 -1
  121. package/dist/react/useRow.test.d.ts +0 -2
  122. package/dist/react/useRow.test.d.ts.map +0 -1
  123. package/dist/react/useRow.test.js +0 -562
  124. package/dist/react/useRow.test.js.map +0 -1
  125. package/dist/react/useTemporaryQuery.d.ts +0 -22
  126. package/dist/react/useTemporaryQuery.d.ts.map +0 -1
  127. package/dist/react/useTemporaryQuery.js +0 -70
  128. package/dist/react/useTemporaryQuery.js.map +0 -1
  129. package/dist/react/useTemporaryQuery.test.d.ts +0 -2
  130. package/dist/react/useTemporaryQuery.test.d.ts.map +0 -1
  131. package/dist/react/useTemporaryQuery.test.js +0 -37
  132. package/dist/react/useTemporaryQuery.test.js.map +0 -1
  133. package/dist/react/utils/stack-info.d.ts.map +0 -1
  134. package/dist/react/utils/stack-info.js.map +0 -1
  135. package/dist/react/utils/useStateRefWithReactiveInput.d.ts +0 -13
  136. package/dist/react/utils/useStateRefWithReactiveInput.d.ts.map +0 -1
  137. package/dist/react/utils/useStateRefWithReactiveInput.js +0 -38
  138. package/dist/react/utils/useStateRefWithReactiveInput.js.map +0 -1
  139. package/src/__tests__/react/fixture.tsx +0 -126
  140. package/src/react/LiveStoreContext.ts +0 -20
  141. package/src/react/LiveStoreProvider.test.tsx +0 -109
  142. package/src/react/LiveStoreProvider.tsx +0 -289
  143. package/src/react/components/LiveList.tsx +0 -84
  144. package/src/react/index.ts +0 -19
  145. package/src/react/useAtom.ts +0 -55
  146. package/src/react/useLocalId.ts +0 -33
  147. package/src/react/useQuery.test.tsx +0 -82
  148. package/src/react/useQuery.ts +0 -105
  149. package/src/react/useRow.test.tsx +0 -699
  150. package/src/react/useRow.ts +0 -180
  151. package/src/react/useTemporaryQuery.test.tsx +0 -56
  152. package/src/react/useTemporaryQuery.ts +0 -121
  153. package/src/react/utils/useStateRefWithReactiveInput.ts +0 -51
  154. /package/dist/{__tests__/react/utils → utils}/stack-info.test.d.ts +0 -0
  155. /package/dist/{__tests__/react/utils → utils/tests}/otel.d.ts +0 -0
  156. /package/dist/{__tests__/react/utils → utils/tests}/otel.js +0 -0
  157. /package/src/{__tests__/react/utils → utils/tests}/otel.ts +0 -0
@@ -1,180 +0,0 @@
1
- import type { QueryInfo } from '@livestore/common'
2
- import { DbSchema } from '@livestore/common/schema'
3
- import { shouldNeverHappen } from '@livestore/utils'
4
- import { ReadonlyRecord } from '@livestore/utils/effect'
5
- import type { SqliteDsl } from 'effect-db-schema'
6
- import React from 'react'
7
-
8
- import type { LiveQuery, ReactivityGraph } from '../index.js'
9
- import type { RowResult } from '../row-query.js'
10
- import { rowQuery } from '../row-query.js'
11
- import { useStore } from './LiveStoreContext.js'
12
- import { useQueryRef } from './useQuery.js'
13
- import { useMakeTemporaryQuery } from './useTemporaryQuery.js'
14
-
15
- export type UseRowResult<TTableDef extends DbSchema.TableDef> = [
16
- row: RowResult<TTableDef>,
17
- setRow: StateSetters<TTableDef>,
18
- query$: LiveQuery<RowResult<TTableDef>, QueryInfo>,
19
- ]
20
-
21
- export type UseRowOptionsDefaulValues<TTableDef extends DbSchema.TableDef> = {
22
- defaultValues?: Partial<RowResult<TTableDef>>
23
- }
24
-
25
- export type UseRowOptionsBase = {
26
- reactivityGraph?: ReactivityGraph
27
- }
28
-
29
- /**
30
- * Similar to `React.useState` but returns a tuple of `[row, setRow, query$]` for a given table where ...
31
- *
32
- * - `row` is the current value of the row (fully decoded according to the table schema)
33
- * - `setRow` is a function that can be used to update the row (values will be encoded according to the table schema)
34
- * - `query$` is a `LiveQuery` that e.g. can be used to subscribe to changes to the row
35
- *
36
- * If the table is a singleton table, `useRow` can be called without an `id` argument. Otherwise, the `id` argument is required.
37
- */
38
- export const useRow: {
39
- <
40
- TTableDef extends DbSchema.TableDef<
41
- DbSchema.DefaultSqliteTableDef,
42
- boolean,
43
- DbSchema.TableOptions & { isSingleton: true; deriveMutations: { enabled: true } }
44
- >,
45
- >(
46
- table: TTableDef,
47
- options?: UseRowOptionsBase,
48
- ): UseRowResult<TTableDef>
49
- <
50
- TTableDef extends DbSchema.TableDef<
51
- DbSchema.DefaultSqliteTableDef,
52
- boolean,
53
- DbSchema.TableOptions & { isSingleton: false; deriveMutations: { enabled: true } }
54
- >,
55
- >(
56
- table: TTableDef,
57
- // TODO adjust so it works with arbitrary primary keys or unique constraints
58
- id: string,
59
- options?: UseRowOptionsBase & UseRowOptionsDefaulValues<TTableDef>,
60
- ): UseRowResult<TTableDef>
61
- } = <
62
- TTableDef extends DbSchema.TableDef<
63
- DbSchema.DefaultSqliteTableDefConstrained,
64
- boolean,
65
- DbSchema.TableOptions & { deriveMutations: { enabled: true } }
66
- >,
67
- >(
68
- table: TTableDef,
69
- idOrOptions?: string | UseRowOptionsBase,
70
- options_?: UseRowOptionsBase & UseRowOptionsDefaulValues<TTableDef>,
71
- ): UseRowResult<TTableDef> => {
72
- const sqliteTableDef = table.sqliteDef
73
- const id = typeof idOrOptions === 'string' ? idOrOptions : undefined
74
- const options: (UseRowOptionsBase & UseRowOptionsDefaulValues<TTableDef>) | undefined =
75
- typeof idOrOptions === 'string' ? options_ : idOrOptions
76
- const { defaultValues, reactivityGraph } = options ?? {}
77
-
78
- type TComponentState = SqliteDsl.FromColumns.RowDecoded<TTableDef['sqliteDef']['columns']>
79
-
80
- const tableName = table.sqliteDef.name
81
-
82
- if (DbSchema.tableHasDerivedMutations(table) === false) {
83
- shouldNeverHappen(`useRow called on table "${tableName}" which does not have 'deriveMutations: true' set`)
84
- }
85
-
86
- const { store } = useStore()
87
-
88
- if (
89
- store.schema.tables.has(table.sqliteDef.name) === false &&
90
- table.sqliteDef.name.startsWith('__livestore') === false
91
- ) {
92
- shouldNeverHappen(`Table "${table.sqliteDef.name}" not found in schema`)
93
- }
94
-
95
- // console.debug('useRow', tableName, id)
96
-
97
- const { query$, otelContext } = useMakeTemporaryQuery(
98
- (otelContext) =>
99
- DbSchema.tableIsSingleton(table)
100
- ? (rowQuery(table, { otelContext, reactivityGraph }) as LiveQuery<RowResult<TTableDef>, QueryInfo>)
101
- : (rowQuery(table as TTableDef & { options: { isSingleton: false } }, id!, {
102
- otelContext,
103
- defaultValues: defaultValues!,
104
- reactivityGraph,
105
- }) as any as LiveQuery<RowResult<TTableDef>, QueryInfo>),
106
- [id!, tableName],
107
- {
108
- otel: {
109
- spanName: `LiveStore:useRow:${tableName}${id === undefined ? '' : `:${id}`}`,
110
- attributes: { id },
111
- },
112
- },
113
- )
114
-
115
- const query$Ref = useQueryRef(query$, otelContext) as React.MutableRefObject<RowResult<TTableDef>>
116
-
117
- const setState = React.useMemo<StateSetters<TTableDef>>(() => {
118
- if (table.isSingleColumn) {
119
- return (newValueOrFn: RowResult<TTableDef>) => {
120
- const newValue = typeof newValueOrFn === 'function' ? newValueOrFn(query$Ref.current) : newValueOrFn
121
- if (query$Ref.current === newValue) return
122
-
123
- // NOTE we need to account for the short-hand syntax for single-column+singleton tables
124
- if (table.options.isSingleton) {
125
- store.mutate(table.update(newValue))
126
- } else {
127
- store.mutate(table.update({ where: { id }, values: { value: newValue } }))
128
- }
129
- // store.mutate(updateMutationForQueryInfo(query$.queryInfo!, { value: newValue }))
130
- }
131
- } else {
132
- const setState = // TODO: do we have a better type for the values that can go in SQLite?
133
- ReadonlyRecord.map(sqliteTableDef.columns, (column, columnName) => (newValueOrFn: any) => {
134
- const newValue =
135
- // @ts-expect-error TODO fix typing
136
- typeof newValueOrFn === 'function' ? newValueOrFn(query$Ref.current[columnName]) : newValueOrFn
137
-
138
- // Don't update the state if it's the same as the value already seen in the component
139
- // @ts-expect-error TODO fix typing
140
- if (query$Ref.current[columnName] === newValue) return
141
-
142
- store.mutate(table.update({ where: { id: id ?? 'singleton' }, values: { [columnName]: newValue } }))
143
- // store.mutate(updateMutationForQueryInfo(query$.queryInfo!, { [columnName]: newValue }))
144
- })
145
-
146
- setState.setMany = (columnValuesOrFn: Partial<TComponentState>) => {
147
- const columnValues =
148
- // @ts-expect-error TODO fix typing
149
- typeof columnValuesOrFn === 'function' ? columnValuesOrFn(query$Ref.current) : columnValuesOrFn
150
-
151
- // TODO use hashing instead
152
- // Don't update the state if it's the same as the value already seen in the component
153
- if (
154
- // @ts-expect-error TODO fix typing
155
- Object.entries(columnValues).every(([columnName, value]) => query$Ref.current[columnName] === value)
156
- ) {
157
- return
158
- }
159
-
160
- store.mutate(table.update({ where: { id: id ?? 'singleton' }, values: columnValues }))
161
- // store.mutate(updateMutationForQueryInfo(query$.queryInfo!, columnValues))
162
- }
163
-
164
- return setState as any
165
- }
166
- }, [id, query$Ref, sqliteTableDef.columns, store, table])
167
-
168
- return [query$Ref.current, setState, query$]
169
- }
170
-
171
- export type Dispatch<A> = (action: A) => void
172
- export type SetStateAction<S> = S | ((previousValue: S) => S)
173
-
174
- export type StateSetters<TTableDef extends DbSchema.TableDef> = TTableDef['isSingleColumn'] extends true
175
- ? Dispatch<SetStateAction<RowResult<TTableDef>>>
176
- : {
177
- [K in keyof RowResult<TTableDef>]: Dispatch<SetStateAction<RowResult<TTableDef>[K]>>
178
- } & {
179
- setMany: Dispatch<SetStateAction<Partial<RowResult<TTableDef>>>>
180
- }
@@ -1,56 +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
-
5
- import { makeTodoMvc, tables, todos } from '../__tests__/react/fixture.js'
6
- import type * as LiveStore from '../index.js'
7
- import { querySQL } from '../reactiveQueries/sql.js'
8
- import * as LiveStoreReact from './index.js'
9
-
10
- describe('useTemporaryQuery', () => {
11
- it('simple', () =>
12
- Effect.gen(function* () {
13
- const { wrapper, store, makeRenderCount } = yield* makeTodoMvc()
14
-
15
- const renderCount = makeRenderCount()
16
-
17
- store.mutate(
18
- todos.insert({ id: 't1', text: 'buy milk', completed: false }),
19
- todos.insert({ id: 't2', text: 'buy bread', completed: false }),
20
- )
21
-
22
- const queryMap = new Map<string, LiveStore.LiveQuery<any>>()
23
-
24
- const { rerender, result, unmount } = renderHook(
25
- (id: string) => {
26
- renderCount.inc()
27
-
28
- return LiveStoreReact.useTemporaryQuery(() => {
29
- const query$ = querySQL(`select * from todos where id = '${id}'`, {
30
- schema: Schema.Array(tables.todos.schema),
31
- })
32
- queryMap.set(id, query$)
33
- return query$
34
- }, id)
35
- },
36
- { wrapper, initialProps: 't1' },
37
- )
38
-
39
- expect(result.current.length).toBe(1)
40
- expect(result.current[0]!.text).toBe('buy milk')
41
- expect(renderCount.val).toBe(1)
42
- expect(queryMap.get('t1')!.runs).toBe(1)
43
-
44
- rerender('t2')
45
-
46
- expect(result.current.length).toBe(1)
47
- expect(result.current[0]!.text).toBe('buy bread')
48
- expect(renderCount.val).toBe(2)
49
- expect(queryMap.get('t1')!.runs).toBe(1)
50
- expect(queryMap.get('t2')!.runs).toBe(1)
51
-
52
- unmount()
53
-
54
- expect(queryMap.get('t2')!.runs).toBe(1)
55
- }).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise))
56
- })
@@ -1,121 +0,0 @@
1
- import type { QueryInfo } from '@livestore/common'
2
- import * as otel from '@opentelemetry/api'
3
- import React from 'react'
4
-
5
- import type { LiveQuery } from '../reactiveQueries/base-class.js'
6
- import { useStore } from './LiveStoreContext.js'
7
- import { useQueryRef } from './useQuery.js'
8
-
9
- // NOTE Given `useMemo` will be called multiple times (e.g. when using React Strict mode or Fast Refresh),
10
- // we are using this cache to avoid starting multiple queries/spans for the same component.
11
- // This is somewhat against some recommended React best practices, but it should be fine in our case below.
12
- // Please definitely open an issue if you see or run into any problems with this approach!
13
- const cache = new Map<
14
- string,
15
- {
16
- rc: number
17
- query$: LiveQuery<any, any>
18
- span: otel.Span
19
- otelContext: otel.Context
20
- }
21
- >()
22
-
23
- export type DepKey = string | number | ReadonlyArray<string | number>
24
-
25
- /**
26
- * Creates a query, subscribes and destroys it when the component unmounts.
27
- *
28
- * The `key` is used to determine whether the a new query should be created or if the existing one should be reused.
29
- */
30
- export const useTemporaryQuery = <TResult>(makeQuery: () => LiveQuery<TResult>, key: DepKey): TResult =>
31
- useTemporaryQueryRef(makeQuery, key).current
32
-
33
- export const useTemporaryQueryRef = <TResult>(
34
- makeQuery: () => LiveQuery<TResult>,
35
- key: DepKey,
36
- ): React.MutableRefObject<TResult> => {
37
- const { query$ } = useMakeTemporaryQuery(makeQuery, key)
38
-
39
- return useQueryRef(query$)
40
- }
41
-
42
- export const useMakeTemporaryQuery = <TResult, TQueryInfo extends QueryInfo>(
43
- makeQuery: (otelContext: otel.Context) => LiveQuery<TResult, TQueryInfo>,
44
- key: DepKey,
45
- options?: {
46
- otel?: {
47
- spanName?: string
48
- attributes?: otel.Attributes
49
- }
50
- },
51
- ): { query$: LiveQuery<TResult, TQueryInfo>; otelContext: otel.Context } => {
52
- const { store } = useStore()
53
- const fullKey = React.useMemo(
54
- // NOTE We're using the `makeQuery` function body string to make sure the key is unique across the app
55
- // TODO we should figure out whether this could cause some problems and/or if there's a better way to do this
56
- () => (Array.isArray(key) ? key.join('-') : key) + '-' + store.reactivityGraph.id + '-' + makeQuery.toString(),
57
- [key, makeQuery, store.reactivityGraph.id],
58
- )
59
- const fullKeyRef = React.useRef<string>()
60
-
61
- const { query$, otelContext } = React.useMemo(() => {
62
- if (fullKeyRef.current !== undefined && fullKeyRef.current !== fullKey) {
63
- // console.debug('fullKey changed, destroying previous', fullKeyRef.current.split('-')[0]!, fullKey.split('-')[0]!)
64
-
65
- const cachedItem = cache.get(fullKeyRef.current)
66
- if (cachedItem !== undefined) {
67
- cachedItem.rc--
68
-
69
- if (cachedItem.rc === 0) {
70
- cachedItem.query$.destroy()
71
- cachedItem.span.end()
72
- cache.delete(fullKeyRef.current)
73
- }
74
- }
75
- }
76
-
77
- const cachedItem = cache.get(fullKey)
78
- if (cachedItem !== undefined) {
79
- cachedItem.rc++
80
-
81
- return cachedItem
82
- }
83
-
84
- const spanName = options?.otel?.spanName ?? `LiveStore:useTemporaryQuery:${key}`
85
-
86
- const span = store.otel.tracer.startSpan(
87
- spanName,
88
- { attributes: options?.otel?.attributes },
89
- store.otel.queriesSpanContext,
90
- )
91
-
92
- const otelContext = otel.trace.setSpan(otel.context.active(), span)
93
-
94
- const query$ = makeQuery(otelContext)
95
-
96
- cache.set(fullKey, { rc: 1, query$, span, otelContext })
97
-
98
- return { query$, otelContext }
99
- // eslint-disable-next-line react-hooks/exhaustive-deps
100
- }, [fullKey])
101
-
102
- fullKeyRef.current = fullKey
103
-
104
- React.useEffect(() => {
105
- return () => {
106
- const cachedItem = cache.get(fullKey)
107
- // NOTE in case the fullKey changed then the query was already destroyed in the useMemo above
108
- if (cachedItem === undefined) return
109
-
110
- cachedItem.rc--
111
-
112
- if (cachedItem.rc === 0) {
113
- cachedItem.query$.destroy()
114
- cachedItem.span.end()
115
- cache.delete(fullKey)
116
- }
117
- }
118
- }, [fullKey])
119
-
120
- return { query$, otelContext }
121
- }
@@ -1,51 +0,0 @@
1
- import React from 'react'
2
-
3
- /**
4
- * A variant of `React.useState` which allows the `inputState` to change over time as well.
5
- * Important: This hook is synchronous / single-render-pass (i.e. doesn't use `useEffect` or `setState` directly).
6
- *
7
- * Notes:
8
- * - 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)
9
- * - This hook might not work properly with React Suspense
10
- * - Also see this Tweet for more potential problems: https://twitter.com/schickling/status/1677317711104278528
11
- *
12
- */
13
- export const useStateRefWithReactiveInput = <T>(
14
- inputState: T,
15
- ): [React.MutableRefObject<T>, (newState: T | ((prev: T) => T)) => void] => {
16
- const [_, rerender] = React.useState(0)
17
-
18
- const lastKnownInputStateRef = React.useRef<T>(inputState)
19
- const stateRef = React.useRef<T>(inputState)
20
-
21
- if (lastKnownInputStateRef.current !== inputState) {
22
- lastKnownInputStateRef.current = inputState
23
-
24
- // NOTE we don't need to re-render here, because the component is already re-rendering due to the `inputState` change
25
- stateRef.current = inputState
26
- }
27
-
28
- const setStateAndRerender = React.useCallback(
29
- (newState: ((prev: T) => T) | T) => {
30
- // @ts-expect-error https://github.com/microsoft/TypeScript/issues/37663
31
- const val = typeof newState === 'function' ? newState(stateRef.current) : newState
32
- stateRef.current = val
33
- rerender((c) => c + 1)
34
- },
35
- [rerender],
36
- )
37
-
38
- return [stateRef, setStateAndRerender]
39
- }
40
-
41
- // Down-side of this implementation: Double render pass due to `setState` call (which forces a re-render)
42
- // Keeping around for now in case `useStateRefWithReactiveInput` doesn't work out
43
- // const _useStateWithReactiveInput = <T>(inputState: T): [T, (newState: T | ((prev: T) => T)) => void] => {
44
- // const [externalState, setExternalState] = React.useState(inputState)
45
-
46
- // if (externalState !== inputState) {
47
- // setExternalState(inputState)
48
- // }
49
-
50
- // return [externalState, setExternalState]
51
- // }