@tanstack/preact-pacer 0.18.0 → 0.19.1
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/dist/async-batcher/index.cjs +3 -3
- package/dist/async-batcher/index.d.cts +2 -2
- package/dist/async-batcher/index.d.ts +2 -2
- package/dist/async-batcher/useAsyncBatcher.cjs +35 -11
- package/dist/async-batcher/useAsyncBatcher.cjs.map +1 -1
- package/dist/async-batcher/useAsyncBatcher.d.cts +45 -10
- package/dist/async-batcher/useAsyncBatcher.d.ts +45 -10
- package/dist/async-batcher/useAsyncBatcher.js +32 -8
- package/dist/async-batcher/useAsyncBatcher.js.map +1 -1
- package/dist/async-debouncer/index.cjs +3 -3
- package/dist/async-debouncer/index.d.cts +2 -2
- package/dist/async-debouncer/index.d.ts +2 -2
- package/dist/async-debouncer/useAsyncDebouncer.cjs +35 -11
- package/dist/async-debouncer/useAsyncDebouncer.cjs.map +1 -1
- package/dist/async-debouncer/useAsyncDebouncer.d.cts +45 -10
- package/dist/async-debouncer/useAsyncDebouncer.d.ts +45 -10
- package/dist/async-debouncer/useAsyncDebouncer.js +32 -8
- package/dist/async-debouncer/useAsyncDebouncer.js.map +1 -1
- package/dist/async-queuer/index.cjs +3 -3
- package/dist/async-queuer/index.d.cts +2 -2
- package/dist/async-queuer/index.d.ts +2 -2
- package/dist/async-queuer/useAsyncQueuedState.cjs.map +1 -1
- package/dist/async-queuer/useAsyncQueuedState.d.cts +2 -2
- package/dist/async-queuer/useAsyncQueuedState.d.ts +2 -2
- package/dist/async-queuer/useAsyncQueuedState.js.map +1 -1
- package/dist/async-queuer/useAsyncQueuer.cjs +35 -11
- package/dist/async-queuer/useAsyncQueuer.cjs.map +1 -1
- package/dist/async-queuer/useAsyncQueuer.d.cts +45 -10
- package/dist/async-queuer/useAsyncQueuer.d.ts +45 -10
- package/dist/async-queuer/useAsyncQueuer.js +32 -8
- package/dist/async-queuer/useAsyncQueuer.js.map +1 -1
- package/dist/async-rate-limiter/index.cjs +3 -3
- package/dist/async-rate-limiter/index.d.cts +2 -2
- package/dist/async-rate-limiter/index.d.ts +2 -2
- package/dist/async-rate-limiter/useAsyncRateLimiter.cjs +35 -11
- package/dist/async-rate-limiter/useAsyncRateLimiter.cjs.map +1 -1
- package/dist/async-rate-limiter/useAsyncRateLimiter.d.cts +45 -10
- package/dist/async-rate-limiter/useAsyncRateLimiter.d.ts +45 -10
- package/dist/async-rate-limiter/useAsyncRateLimiter.js +32 -8
- package/dist/async-rate-limiter/useAsyncRateLimiter.js.map +1 -1
- package/dist/async-retryer/index.cjs +3 -3
- package/dist/async-throttler/index.cjs +3 -3
- package/dist/async-throttler/index.d.cts +2 -2
- package/dist/async-throttler/index.d.ts +2 -2
- package/dist/async-throttler/useAsyncThrottler.cjs +35 -11
- package/dist/async-throttler/useAsyncThrottler.cjs.map +1 -1
- package/dist/async-throttler/useAsyncThrottler.d.cts +45 -10
- package/dist/async-throttler/useAsyncThrottler.d.ts +45 -10
- package/dist/async-throttler/useAsyncThrottler.js +32 -8
- package/dist/async-throttler/useAsyncThrottler.js.map +1 -1
- package/dist/batcher/index.cjs +3 -3
- package/dist/batcher/useBatcher.cjs +35 -11
- package/dist/batcher/useBatcher.cjs.map +1 -1
- package/dist/batcher/useBatcher.d.cts +42 -7
- package/dist/batcher/useBatcher.d.ts +42 -7
- package/dist/batcher/useBatcher.js +32 -8
- package/dist/batcher/useBatcher.js.map +1 -1
- package/dist/debouncer/index.cjs +3 -3
- package/dist/debouncer/useDebouncer.cjs +35 -11
- package/dist/debouncer/useDebouncer.cjs.map +1 -1
- package/dist/debouncer/useDebouncer.d.cts +42 -7
- package/dist/debouncer/useDebouncer.d.ts +42 -7
- package/dist/debouncer/useDebouncer.js +32 -8
- package/dist/debouncer/useDebouncer.js.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/provider/PacerProvider.d.cts +1 -1
- package/dist/queuer/index.cjs +3 -3
- package/dist/queuer/useQueuer.cjs +35 -11
- package/dist/queuer/useQueuer.cjs.map +1 -1
- package/dist/queuer/useQueuer.d.cts +42 -7
- package/dist/queuer/useQueuer.d.ts +42 -7
- package/dist/queuer/useQueuer.js +32 -8
- package/dist/queuer/useQueuer.js.map +1 -1
- package/dist/rate-limiter/index.cjs +3 -3
- package/dist/rate-limiter/useRateLimiter.cjs +35 -11
- package/dist/rate-limiter/useRateLimiter.cjs.map +1 -1
- package/dist/rate-limiter/useRateLimiter.d.cts +42 -7
- package/dist/rate-limiter/useRateLimiter.d.ts +42 -7
- package/dist/rate-limiter/useRateLimiter.js +32 -8
- package/dist/rate-limiter/useRateLimiter.js.map +1 -1
- package/dist/throttler/index.cjs +3 -3
- package/dist/throttler/useThrottler.cjs +35 -11
- package/dist/throttler/useThrottler.cjs.map +1 -1
- package/dist/throttler/useThrottler.d.cts +42 -7
- package/dist/throttler/useThrottler.d.ts +42 -7
- package/dist/throttler/useThrottler.js +32 -8
- package/dist/throttler/useThrottler.js.map +1 -1
- package/dist/types/index.cjs +3 -3
- package/dist/utils/index.cjs +3 -3
- package/package.json +3 -3
- package/src/async-batcher/useAsyncBatcher.ts +64 -13
- package/src/async-debouncer/useAsyncDebouncer.ts +64 -13
- package/src/async-queuer/useAsyncQueuedState.ts +2 -2
- package/src/async-queuer/useAsyncQueuer.ts +64 -13
- package/src/async-rate-limiter/useAsyncRateLimiter.ts +64 -13
- package/src/async-throttler/useAsyncThrottler.ts +64 -13
- package/src/batcher/useBatcher.ts +61 -8
- package/src/debouncer/useDebouncer.ts +61 -8
- package/src/queuer/useQueuer.ts +61 -8
- package/src/rate-limiter/useRateLimiter.ts +61 -8
- package/src/throttler/useThrottler.ts +61 -8
|
@@ -7,11 +7,29 @@ import type {
|
|
|
7
7
|
AsyncQueuerOptions,
|
|
8
8
|
AsyncQueuerState,
|
|
9
9
|
} from '@tanstack/pacer/async-queuer'
|
|
10
|
+
import type { ComponentChildren } from 'preact'
|
|
10
11
|
|
|
11
|
-
export interface
|
|
12
|
+
export interface PreactAsyncQueuer<TValue, TSelected = {}> extends Omit<
|
|
12
13
|
AsyncQueuer<TValue>,
|
|
13
14
|
'store'
|
|
14
15
|
> {
|
|
16
|
+
/**
|
|
17
|
+
* A Preact HOC (Higher Order Component) that allows you to subscribe to the async queuer state.
|
|
18
|
+
*
|
|
19
|
+
* This is useful for opting into state re-renders for specific parts of the queuer state
|
|
20
|
+
* deep in your component tree without needing to pass a selector to the hook.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* <queuer.Subscribe selector={(state) => ({ size: state.size })}>
|
|
24
|
+
* {({ size }) => (
|
|
25
|
+
* <div>Queue Size: {size}</div>
|
|
26
|
+
* )}
|
|
27
|
+
* </queuer.Subscribe>
|
|
28
|
+
*/
|
|
29
|
+
Subscribe: <TSelected>(props: {
|
|
30
|
+
selector: (state: AsyncQueuerState<TValue>) => TSelected
|
|
31
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
32
|
+
}) => ComponentChildren
|
|
15
33
|
/**
|
|
16
34
|
* Reactive state that will be updated and re-rendered when the queuer state changes
|
|
17
35
|
*
|
|
@@ -50,14 +68,24 @@ export interface ReactAsyncQueuer<TValue, TSelected = {}> extends Omit<
|
|
|
50
68
|
*
|
|
51
69
|
* ## State Management and Selector
|
|
52
70
|
*
|
|
53
|
-
* The hook uses TanStack Store for reactive state management.
|
|
54
|
-
*
|
|
55
|
-
*
|
|
71
|
+
* The hook uses TanStack Store for reactive state management. You can subscribe to state changes
|
|
72
|
+
* in two ways:
|
|
73
|
+
*
|
|
74
|
+
* **1. Using `queuer.Subscribe` HOC (Recommended for component tree subscriptions)**
|
|
75
|
+
*
|
|
76
|
+
* Use the `Subscribe` HOC to subscribe to state changes deep in your component tree without
|
|
77
|
+
* needing to pass a selector to the hook. This is ideal when you want to subscribe to state
|
|
78
|
+
* in child components.
|
|
79
|
+
*
|
|
80
|
+
* **2. Using the `selector` parameter (For hook-level subscriptions)**
|
|
81
|
+
*
|
|
82
|
+
* The `selector` parameter allows you to specify which state changes will trigger a re-render
|
|
83
|
+
* at the hook level, optimizing performance by preventing unnecessary re-renders when irrelevant
|
|
84
|
+
* state changes occur.
|
|
56
85
|
*
|
|
57
86
|
* **By default, there will be no reactive state subscriptions** and you must opt-in to state
|
|
58
|
-
* tracking by providing a selector function. This prevents unnecessary
|
|
59
|
-
* full control over when your component updates.
|
|
60
|
-
* component re-render when the selected state values change.
|
|
87
|
+
* tracking by providing a selector function or using the `Subscribe` HOC. This prevents unnecessary
|
|
88
|
+
* re-renders and gives you full control over when your component updates.
|
|
61
89
|
*
|
|
62
90
|
* Available state properties:
|
|
63
91
|
* - `activeItems`: Items currently being processed by the queuer
|
|
@@ -88,7 +116,14 @@ export interface ReactAsyncQueuer<TValue, TSelected = {}> extends Omit<
|
|
|
88
116
|
* { concurrency: 2, maxSize: 100, started: false }
|
|
89
117
|
* );
|
|
90
118
|
*
|
|
91
|
-
* //
|
|
119
|
+
* // Subscribe to state changes deep in component tree using Subscribe HOC
|
|
120
|
+
* <asyncQueuer.Subscribe selector={(state) => ({ size: state.size })}>
|
|
121
|
+
* {({ size }) => (
|
|
122
|
+
* <div>Queue Size: {size}</div>
|
|
123
|
+
* )}
|
|
124
|
+
* </asyncQueuer.Subscribe>
|
|
125
|
+
*
|
|
126
|
+
* // Opt-in to re-render when queue size changes at hook level (optimized for displaying queue length)
|
|
92
127
|
* const asyncQueuer = useAsyncQueuer(
|
|
93
128
|
* async (item) => {
|
|
94
129
|
* const result = await processItem(item);
|
|
@@ -172,15 +207,31 @@ export function useAsyncQueuer<TValue, TSelected = {}>(
|
|
|
172
207
|
options: AsyncQueuerOptions<TValue> = {},
|
|
173
208
|
selector: (state: AsyncQueuerState<TValue>) => TSelected = () =>
|
|
174
209
|
({}) as TSelected,
|
|
175
|
-
):
|
|
210
|
+
): PreactAsyncQueuer<TValue, TSelected> {
|
|
176
211
|
const mergedOptions = {
|
|
177
212
|
...useDefaultPacerOptions().asyncQueuer,
|
|
178
213
|
...options,
|
|
179
214
|
} as AsyncQueuerOptions<TValue>
|
|
180
215
|
|
|
181
|
-
const [asyncQueuer] = useState(
|
|
182
|
-
|
|
183
|
-
|
|
216
|
+
const [asyncQueuer] = useState(() => {
|
|
217
|
+
const queuerInstance = new AsyncQueuer<TValue>(
|
|
218
|
+
fn,
|
|
219
|
+
mergedOptions,
|
|
220
|
+
) as unknown as PreactAsyncQueuer<TValue, TSelected>
|
|
221
|
+
|
|
222
|
+
queuerInstance.Subscribe = function Subscribe<TSelected>(props: {
|
|
223
|
+
selector: (state: AsyncQueuerState<TValue>) => TSelected
|
|
224
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
225
|
+
}) {
|
|
226
|
+
const selected = useStore(queuerInstance.store, props.selector)
|
|
227
|
+
|
|
228
|
+
return typeof props.children === 'function'
|
|
229
|
+
? props.children(selected)
|
|
230
|
+
: props.children
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return queuerInstance
|
|
234
|
+
})
|
|
184
235
|
|
|
185
236
|
asyncQueuer.fn = fn
|
|
186
237
|
asyncQueuer.setOptions(mergedOptions)
|
|
@@ -192,7 +243,7 @@ export function useAsyncQueuer<TValue, TSelected = {}>(
|
|
|
192
243
|
({
|
|
193
244
|
...asyncQueuer,
|
|
194
245
|
state,
|
|
195
|
-
}) as
|
|
246
|
+
}) as PreactAsyncQueuer<TValue, TSelected>, // omit `store` in favor of `state`
|
|
196
247
|
[asyncQueuer, state],
|
|
197
248
|
)
|
|
198
249
|
}
|
|
@@ -8,11 +8,29 @@ import type {
|
|
|
8
8
|
AsyncRateLimiterOptions,
|
|
9
9
|
AsyncRateLimiterState,
|
|
10
10
|
} from '@tanstack/pacer/async-rate-limiter'
|
|
11
|
+
import type { ComponentChildren } from 'preact'
|
|
11
12
|
|
|
12
|
-
export interface
|
|
13
|
+
export interface PreactAsyncRateLimiter<
|
|
13
14
|
TFn extends AnyAsyncFunction,
|
|
14
15
|
TSelected = {},
|
|
15
16
|
> extends Omit<AsyncRateLimiter<TFn>, 'store'> {
|
|
17
|
+
/**
|
|
18
|
+
* A Preact HOC (Higher Order Component) that allows you to subscribe to the async rate limiter state.
|
|
19
|
+
*
|
|
20
|
+
* This is useful for opting into state re-renders for specific parts of the rate limiter state
|
|
21
|
+
* deep in your component tree without needing to pass a selector to the hook.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* <rateLimiter.Subscribe selector={(state) => ({ rejectionCount: state.rejectionCount })}>
|
|
25
|
+
* {({ rejectionCount }) => (
|
|
26
|
+
* <div>Rejections: {rejectionCount}</div>
|
|
27
|
+
* )}
|
|
28
|
+
* </rateLimiter.Subscribe>
|
|
29
|
+
*/
|
|
30
|
+
Subscribe: <TSelected>(props: {
|
|
31
|
+
selector: (state: AsyncRateLimiterState<TFn>) => TSelected
|
|
32
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
33
|
+
}) => ComponentChildren
|
|
16
34
|
/**
|
|
17
35
|
* Reactive state that will be updated and re-rendered when the rate limiter state changes
|
|
18
36
|
*
|
|
@@ -57,14 +75,24 @@ export interface ReactAsyncRateLimiter<
|
|
|
57
75
|
*
|
|
58
76
|
* ## State Management and Selector
|
|
59
77
|
*
|
|
60
|
-
* The hook uses TanStack Store for reactive state management.
|
|
61
|
-
*
|
|
62
|
-
*
|
|
78
|
+
* The hook uses TanStack Store for reactive state management. You can subscribe to state changes
|
|
79
|
+
* in two ways:
|
|
80
|
+
*
|
|
81
|
+
* **1. Using `rateLimiter.Subscribe` HOC (Recommended for component tree subscriptions)**
|
|
82
|
+
*
|
|
83
|
+
* Use the `Subscribe` HOC to subscribe to state changes deep in your component tree without
|
|
84
|
+
* needing to pass a selector to the hook. This is ideal when you want to subscribe to state
|
|
85
|
+
* in child components.
|
|
86
|
+
*
|
|
87
|
+
* **2. Using the `selector` parameter (For hook-level subscriptions)**
|
|
88
|
+
*
|
|
89
|
+
* The `selector` parameter allows you to specify which state changes will trigger a re-render
|
|
90
|
+
* at the hook level, optimizing performance by preventing unnecessary re-renders when irrelevant
|
|
91
|
+
* state changes occur.
|
|
63
92
|
*
|
|
64
93
|
* **By default, there will be no reactive state subscriptions** and you must opt-in to state
|
|
65
|
-
* tracking by providing a selector function. This prevents unnecessary
|
|
66
|
-
* full control over when your component updates.
|
|
67
|
-
* component re-render when the selected state values change.
|
|
94
|
+
* tracking by providing a selector function or using the `Subscribe` HOC. This prevents unnecessary
|
|
95
|
+
* re-renders and gives you full control over when your component updates.
|
|
68
96
|
*
|
|
69
97
|
* Available state properties:
|
|
70
98
|
* - `errorCount`: Number of function executions that have resulted in errors
|
|
@@ -86,7 +114,14 @@ export interface ReactAsyncRateLimiter<
|
|
|
86
114
|
* { limit: 5, window: 1000 } // 5 calls per second
|
|
87
115
|
* );
|
|
88
116
|
*
|
|
89
|
-
* //
|
|
117
|
+
* // Subscribe to state changes deep in component tree using Subscribe HOC
|
|
118
|
+
* <asyncRateLimiter.Subscribe selector={(state) => ({ rejectionCount: state.rejectionCount })}>
|
|
119
|
+
* {({ rejectionCount }) => (
|
|
120
|
+
* <div>Rejections: {rejectionCount}</div>
|
|
121
|
+
* )}
|
|
122
|
+
* </asyncRateLimiter.Subscribe>
|
|
123
|
+
*
|
|
124
|
+
* // Opt-in to re-render when execution state changes at hook level (optimized for loading indicators)
|
|
90
125
|
* const asyncRateLimiter = useAsyncRateLimiter(
|
|
91
126
|
* async (id: string) => {
|
|
92
127
|
* const data = await api.fetchData(id);
|
|
@@ -184,15 +219,31 @@ export function useAsyncRateLimiter<
|
|
|
184
219
|
options: AsyncRateLimiterOptions<TFn>,
|
|
185
220
|
selector: (state: AsyncRateLimiterState<TFn>) => TSelected = () =>
|
|
186
221
|
({}) as TSelected,
|
|
187
|
-
):
|
|
222
|
+
): PreactAsyncRateLimiter<TFn, TSelected> {
|
|
188
223
|
const mergedOptions = {
|
|
189
224
|
...useDefaultPacerOptions().asyncRateLimiter,
|
|
190
225
|
...options,
|
|
191
226
|
} as AsyncRateLimiterOptions<TFn>
|
|
192
227
|
|
|
193
|
-
const [asyncRateLimiter] = useState(
|
|
194
|
-
|
|
195
|
-
|
|
228
|
+
const [asyncRateLimiter] = useState(() => {
|
|
229
|
+
const rateLimiterInstance = new AsyncRateLimiter<TFn>(
|
|
230
|
+
fn,
|
|
231
|
+
mergedOptions,
|
|
232
|
+
) as unknown as PreactAsyncRateLimiter<TFn, TSelected>
|
|
233
|
+
|
|
234
|
+
rateLimiterInstance.Subscribe = function Subscribe<TSelected>(props: {
|
|
235
|
+
selector: (state: AsyncRateLimiterState<TFn>) => TSelected
|
|
236
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
237
|
+
}) {
|
|
238
|
+
const selected = useStore(rateLimiterInstance.store, props.selector)
|
|
239
|
+
|
|
240
|
+
return typeof props.children === 'function'
|
|
241
|
+
? props.children(selected)
|
|
242
|
+
: props.children
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return rateLimiterInstance
|
|
246
|
+
})
|
|
196
247
|
|
|
197
248
|
asyncRateLimiter.fn = fn
|
|
198
249
|
asyncRateLimiter.setOptions(mergedOptions)
|
|
@@ -204,7 +255,7 @@ export function useAsyncRateLimiter<
|
|
|
204
255
|
({
|
|
205
256
|
...asyncRateLimiter,
|
|
206
257
|
state,
|
|
207
|
-
}) as
|
|
258
|
+
}) as PreactAsyncRateLimiter<TFn, TSelected>, // omit `store` in favor of `state`
|
|
208
259
|
[asyncRateLimiter, state],
|
|
209
260
|
)
|
|
210
261
|
}
|
|
@@ -8,11 +8,29 @@ import type {
|
|
|
8
8
|
AsyncThrottlerOptions,
|
|
9
9
|
AsyncThrottlerState,
|
|
10
10
|
} from '@tanstack/pacer/async-throttler'
|
|
11
|
+
import type { ComponentChildren } from 'preact'
|
|
11
12
|
|
|
12
|
-
export interface
|
|
13
|
+
export interface PreactAsyncThrottler<
|
|
13
14
|
TFn extends AnyAsyncFunction,
|
|
14
15
|
TSelected = {},
|
|
15
16
|
> extends Omit<AsyncThrottler<TFn>, 'store'> {
|
|
17
|
+
/**
|
|
18
|
+
* A Preact HOC (Higher Order Component) that allows you to subscribe to the async throttler state.
|
|
19
|
+
*
|
|
20
|
+
* This is useful for opting into state re-renders for specific parts of the throttler state
|
|
21
|
+
* deep in your component tree without needing to pass a selector to the hook.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* <throttler.Subscribe selector={(state) => ({ isPending: state.isPending })}>
|
|
25
|
+
* {({ isPending }) => (
|
|
26
|
+
* <div>{isPending ? 'Loading...' : 'Ready'}</div>
|
|
27
|
+
* )}
|
|
28
|
+
* </throttler.Subscribe>
|
|
29
|
+
*/
|
|
30
|
+
Subscribe: <TSelected>(props: {
|
|
31
|
+
selector: (state: AsyncThrottlerState<TFn>) => TSelected
|
|
32
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
33
|
+
}) => ComponentChildren
|
|
16
34
|
/**
|
|
17
35
|
* Reactive state that will be updated and re-rendered when the throttler state changes
|
|
18
36
|
*
|
|
@@ -50,14 +68,24 @@ export interface ReactAsyncThrottler<
|
|
|
50
68
|
*
|
|
51
69
|
* ## State Management and Selector
|
|
52
70
|
*
|
|
53
|
-
* The hook uses TanStack Store for reactive state management.
|
|
54
|
-
*
|
|
55
|
-
*
|
|
71
|
+
* The hook uses TanStack Store for reactive state management. You can subscribe to state changes
|
|
72
|
+
* in two ways:
|
|
73
|
+
*
|
|
74
|
+
* **1. Using `throttler.Subscribe` HOC (Recommended for component tree subscriptions)**
|
|
75
|
+
*
|
|
76
|
+
* Use the `Subscribe` HOC to subscribe to state changes deep in your component tree without
|
|
77
|
+
* needing to pass a selector to the hook. This is ideal when you want to subscribe to state
|
|
78
|
+
* in child components.
|
|
79
|
+
*
|
|
80
|
+
* **2. Using the `selector` parameter (For hook-level subscriptions)**
|
|
81
|
+
*
|
|
82
|
+
* The `selector` parameter allows you to specify which state changes will trigger a re-render
|
|
83
|
+
* at the hook level, optimizing performance by preventing unnecessary re-renders when irrelevant
|
|
84
|
+
* state changes occur.
|
|
56
85
|
*
|
|
57
86
|
* **By default, there will be no reactive state subscriptions** and you must opt-in to state
|
|
58
|
-
* tracking by providing a selector function. This prevents unnecessary
|
|
59
|
-
* full control over when your component updates.
|
|
60
|
-
* component re-render when the selected state values change.
|
|
87
|
+
* tracking by providing a selector function or using the `Subscribe` HOC. This prevents unnecessary
|
|
88
|
+
* re-renders and gives you full control over when your component updates.
|
|
61
89
|
*
|
|
62
90
|
* Available state properties:
|
|
63
91
|
* - `errorCount`: Number of function executions that have resulted in errors
|
|
@@ -82,7 +110,14 @@ export interface ReactAsyncThrottler<
|
|
|
82
110
|
* { wait: 1000 }
|
|
83
111
|
* );
|
|
84
112
|
*
|
|
85
|
-
* //
|
|
113
|
+
* // Subscribe to state changes deep in component tree using Subscribe HOC
|
|
114
|
+
* <asyncThrottler.Subscribe selector={(state) => ({ isPending: state.isPending })}>
|
|
115
|
+
* {({ isPending }) => (
|
|
116
|
+
* <div>{isPending ? 'Processing...' : 'Ready'}</div>
|
|
117
|
+
* )}
|
|
118
|
+
* </asyncThrottler.Subscribe>
|
|
119
|
+
*
|
|
120
|
+
* // Opt-in to re-render when execution state changes at hook level (optimized for loading indicators)
|
|
86
121
|
* const asyncThrottler = useAsyncThrottler(
|
|
87
122
|
* async (id: string) => {
|
|
88
123
|
* const data = await api.fetchData(id);
|
|
@@ -163,15 +198,31 @@ export function useAsyncThrottler<TFn extends AnyAsyncFunction, TSelected = {}>(
|
|
|
163
198
|
options: AsyncThrottlerOptions<TFn>,
|
|
164
199
|
selector: (state: AsyncThrottlerState<TFn>) => TSelected = () =>
|
|
165
200
|
({}) as TSelected,
|
|
166
|
-
):
|
|
201
|
+
): PreactAsyncThrottler<TFn, TSelected> {
|
|
167
202
|
const mergedOptions = {
|
|
168
203
|
...useDefaultPacerOptions().asyncThrottler,
|
|
169
204
|
...options,
|
|
170
205
|
} as AsyncThrottlerOptions<TFn>
|
|
171
206
|
|
|
172
|
-
const [asyncThrottler] = useState(
|
|
173
|
-
|
|
174
|
-
|
|
207
|
+
const [asyncThrottler] = useState(() => {
|
|
208
|
+
const throttlerInstance = new AsyncThrottler<TFn>(
|
|
209
|
+
fn,
|
|
210
|
+
mergedOptions,
|
|
211
|
+
) as unknown as PreactAsyncThrottler<TFn, TSelected>
|
|
212
|
+
|
|
213
|
+
throttlerInstance.Subscribe = function Subscribe<TSelected>(props: {
|
|
214
|
+
selector: (state: AsyncThrottlerState<TFn>) => TSelected
|
|
215
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
216
|
+
}) {
|
|
217
|
+
const selected = useStore(throttlerInstance.store, props.selector)
|
|
218
|
+
|
|
219
|
+
return typeof props.children === 'function'
|
|
220
|
+
? props.children(selected)
|
|
221
|
+
: props.children
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return throttlerInstance
|
|
225
|
+
})
|
|
175
226
|
|
|
176
227
|
asyncThrottler.fn = fn
|
|
177
228
|
asyncThrottler.setOptions(mergedOptions)
|
|
@@ -187,7 +238,7 @@ export function useAsyncThrottler<TFn extends AnyAsyncFunction, TSelected = {}>(
|
|
|
187
238
|
({
|
|
188
239
|
...asyncThrottler,
|
|
189
240
|
state,
|
|
190
|
-
}) as
|
|
241
|
+
}) as PreactAsyncThrottler<TFn, TSelected>, // omit `store` in favor of `state`
|
|
191
242
|
[asyncThrottler, state],
|
|
192
243
|
)
|
|
193
244
|
}
|
|
@@ -4,11 +4,29 @@ import { useStore } from '@tanstack/preact-store'
|
|
|
4
4
|
import { useDefaultPacerOptions } from '../provider/PacerProvider'
|
|
5
5
|
import type { Store } from '@tanstack/preact-store'
|
|
6
6
|
import type { BatcherOptions, BatcherState } from '@tanstack/pacer/batcher'
|
|
7
|
+
import type { ComponentChildren } from 'preact'
|
|
7
8
|
|
|
8
9
|
export interface PreactBatcher<TValue, TSelected = {}> extends Omit<
|
|
9
10
|
Batcher<TValue>,
|
|
10
11
|
'store'
|
|
11
12
|
> {
|
|
13
|
+
/**
|
|
14
|
+
* A Preact HOC (Higher Order Component) that allows you to subscribe to the batcher state.
|
|
15
|
+
*
|
|
16
|
+
* This is useful for opting into state re-renders for specific parts of the batcher state
|
|
17
|
+
* deep in your component tree without needing to pass a selector to the hook.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <batcher.Subscribe selector={(state) => ({ size: state.size })}>
|
|
21
|
+
* {({ size }) => (
|
|
22
|
+
* <div>Batch Size: {size}</div>
|
|
23
|
+
* )}
|
|
24
|
+
* </batcher.Subscribe>
|
|
25
|
+
*/
|
|
26
|
+
Subscribe: <TSelected>(props: {
|
|
27
|
+
selector: (state: BatcherState<TValue>) => TSelected
|
|
28
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
29
|
+
}) => ComponentChildren
|
|
12
30
|
/**
|
|
13
31
|
* Reactive state that will be updated and re-rendered when the batcher state changes
|
|
14
32
|
*
|
|
@@ -37,14 +55,24 @@ export interface PreactBatcher<TValue, TSelected = {}> extends Omit<
|
|
|
37
55
|
*
|
|
38
56
|
* ## State Management and Selector
|
|
39
57
|
*
|
|
40
|
-
* The hook uses TanStack Store for reactive state management.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
58
|
+
* The hook uses TanStack Store for reactive state management. You can subscribe to state changes
|
|
59
|
+
* in two ways:
|
|
60
|
+
*
|
|
61
|
+
* **1. Using `batcher.Subscribe` HOC (Recommended for component tree subscriptions)**
|
|
62
|
+
*
|
|
63
|
+
* Use the `Subscribe` HOC to subscribe to state changes deep in your component tree without
|
|
64
|
+
* needing to pass a selector to the hook. This is ideal when you want to subscribe to state
|
|
65
|
+
* in child components.
|
|
66
|
+
*
|
|
67
|
+
* **2. Using the `selector` parameter (For hook-level subscriptions)**
|
|
68
|
+
*
|
|
69
|
+
* The `selector` parameter allows you to specify which state changes will trigger a re-render
|
|
70
|
+
* at the hook level, optimizing performance by preventing unnecessary re-renders when irrelevant
|
|
71
|
+
* state changes occur.
|
|
43
72
|
*
|
|
44
73
|
* **By default, there will be no reactive state subscriptions** and you must opt-in to state
|
|
45
|
-
* tracking by providing a selector function. This prevents unnecessary
|
|
46
|
-
* full control over when your component updates.
|
|
47
|
-
* component re-render when the selected state values change.
|
|
74
|
+
* tracking by providing a selector function or using the `Subscribe` HOC. This prevents unnecessary
|
|
75
|
+
* re-renders and gives you full control over when your component updates.
|
|
48
76
|
*
|
|
49
77
|
* Available state properties:
|
|
50
78
|
* - `executionCount`: Number of batch executions that have been completed
|
|
@@ -64,7 +92,14 @@ export interface PreactBatcher<TValue, TSelected = {}> extends Omit<
|
|
|
64
92
|
* { maxSize: 5, wait: 2000 }
|
|
65
93
|
* );
|
|
66
94
|
*
|
|
67
|
-
* //
|
|
95
|
+
* // Subscribe to state changes deep in component tree using Subscribe HOC
|
|
96
|
+
* <batcher.Subscribe selector={(state) => ({ size: state.size })}>
|
|
97
|
+
* {({ size }) => (
|
|
98
|
+
* <div>Batch Size: {size}</div>
|
|
99
|
+
* )}
|
|
100
|
+
* </batcher.Subscribe>
|
|
101
|
+
*
|
|
102
|
+
* // Opt-in to re-render when batch size changes at hook level (optimized for displaying queue size)
|
|
68
103
|
* const batcher = useBatcher<number>(
|
|
69
104
|
* (items) => console.log('Processing batch:', items),
|
|
70
105
|
* { maxSize: 5, wait: 2000 },
|
|
@@ -132,7 +167,25 @@ export function useBatcher<TValue, TSelected = {}>(
|
|
|
132
167
|
...options,
|
|
133
168
|
} as BatcherOptions<TValue>
|
|
134
169
|
|
|
135
|
-
const [batcher] = useState(() =>
|
|
170
|
+
const [batcher] = useState(() => {
|
|
171
|
+
const batcherInstance = new Batcher<TValue>(
|
|
172
|
+
fn,
|
|
173
|
+
mergedOptions,
|
|
174
|
+
) as unknown as PreactBatcher<TValue, TSelected>
|
|
175
|
+
|
|
176
|
+
batcherInstance.Subscribe = function Subscribe<TSelected>(props: {
|
|
177
|
+
selector: (state: BatcherState<TValue>) => TSelected
|
|
178
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
179
|
+
}) {
|
|
180
|
+
const selected = useStore(batcherInstance.store, props.selector)
|
|
181
|
+
|
|
182
|
+
return typeof props.children === 'function'
|
|
183
|
+
? props.children(selected)
|
|
184
|
+
: props.children
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return batcherInstance
|
|
188
|
+
})
|
|
136
189
|
|
|
137
190
|
batcher.fn = fn
|
|
138
191
|
batcher.setOptions(mergedOptions)
|
|
@@ -8,11 +8,29 @@ import type {
|
|
|
8
8
|
DebouncerState,
|
|
9
9
|
} from '@tanstack/pacer/debouncer'
|
|
10
10
|
import type { AnyFunction } from '@tanstack/pacer/types'
|
|
11
|
+
import type { ComponentChildren } from 'preact'
|
|
11
12
|
|
|
12
13
|
export interface PreactDebouncer<
|
|
13
14
|
TFn extends AnyFunction,
|
|
14
15
|
TSelected = {},
|
|
15
16
|
> extends Omit<Debouncer<TFn>, 'store'> {
|
|
17
|
+
/**
|
|
18
|
+
* A Preact HOC (Higher Order Component) that allows you to subscribe to the debouncer state.
|
|
19
|
+
*
|
|
20
|
+
* This is useful for opting into state re-renders for specific parts of the debouncer state
|
|
21
|
+
* deep in your component tree without needing to pass a selector to the hook.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* <debouncer.Subscribe selector={(state) => ({ isPending: state.isPending })}>
|
|
25
|
+
* {({ isPending }) => (
|
|
26
|
+
* <div>{isPending ? 'Loading...' : 'Ready'}</div>
|
|
27
|
+
* )}
|
|
28
|
+
* </debouncer.Subscribe>
|
|
29
|
+
*/
|
|
30
|
+
Subscribe: <TSelected>(props: {
|
|
31
|
+
selector: (state: DebouncerState<TFn>) => TSelected
|
|
32
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
33
|
+
}) => ComponentChildren
|
|
16
34
|
/**
|
|
17
35
|
* Reactive state that will be updated and re-rendered when the debouncer state changes
|
|
18
36
|
*
|
|
@@ -44,14 +62,24 @@ export interface PreactDebouncer<
|
|
|
44
62
|
*
|
|
45
63
|
* ## State Management and Selector
|
|
46
64
|
*
|
|
47
|
-
* The hook uses TanStack Store for reactive state management.
|
|
48
|
-
*
|
|
49
|
-
*
|
|
65
|
+
* The hook uses TanStack Store for reactive state management. You can subscribe to state changes
|
|
66
|
+
* in two ways:
|
|
67
|
+
*
|
|
68
|
+
* **1. Using `debouncer.Subscribe` HOC (Recommended for component tree subscriptions)**
|
|
69
|
+
*
|
|
70
|
+
* Use the `Subscribe` HOC to subscribe to state changes deep in your component tree without
|
|
71
|
+
* needing to pass a selector to the hook. This is ideal when you want to subscribe to state
|
|
72
|
+
* in child components.
|
|
73
|
+
*
|
|
74
|
+
* **2. Using the `selector` parameter (For hook-level subscriptions)**
|
|
75
|
+
*
|
|
76
|
+
* The `selector` parameter allows you to specify which state changes will trigger a re-render
|
|
77
|
+
* at the hook level, optimizing performance by preventing unnecessary re-renders when irrelevant
|
|
78
|
+
* state changes occur.
|
|
50
79
|
*
|
|
51
80
|
* **By default, there will be no reactive state subscriptions** and you must opt-in to state
|
|
52
|
-
* tracking by providing a selector function. This prevents unnecessary
|
|
53
|
-
* full control over when your component updates.
|
|
54
|
-
* component re-render when the selected state values change.
|
|
81
|
+
* tracking by providing a selector function or using the `Subscribe` HOC. This prevents unnecessary
|
|
82
|
+
* re-renders and gives you full control over when your component updates.
|
|
55
83
|
*
|
|
56
84
|
* Available state properties:
|
|
57
85
|
* - `canLeadingExecute`: Whether the debouncer can execute on the leading edge
|
|
@@ -68,7 +96,14 @@ export interface PreactDebouncer<
|
|
|
68
96
|
* { wait: 500 }
|
|
69
97
|
* );
|
|
70
98
|
*
|
|
71
|
-
* //
|
|
99
|
+
* // Subscribe to state changes deep in component tree using Subscribe HOC
|
|
100
|
+
* <searchDebouncer.Subscribe selector={(state) => ({ isPending: state.isPending })}>
|
|
101
|
+
* {({ isPending }) => (
|
|
102
|
+
* <div>{isPending ? 'Searching...' : 'Ready'}</div>
|
|
103
|
+
* )}
|
|
104
|
+
* </searchDebouncer.Subscribe>
|
|
105
|
+
*
|
|
106
|
+
* // Opt-in to re-render when isPending changes at hook level (optimized for loading states)
|
|
72
107
|
* const searchDebouncer = useDebouncer(
|
|
73
108
|
* (query: string) => fetchSearchResults(query),
|
|
74
109
|
* { wait: 500 },
|
|
@@ -112,7 +147,25 @@ export function useDebouncer<TFn extends AnyFunction, TSelected = {}>(
|
|
|
112
147
|
...options,
|
|
113
148
|
} as DebouncerOptions<TFn>
|
|
114
149
|
|
|
115
|
-
const [debouncer] = useState(() =>
|
|
150
|
+
const [debouncer] = useState(() => {
|
|
151
|
+
const debouncerInstance = new Debouncer(
|
|
152
|
+
fn,
|
|
153
|
+
mergedOptions,
|
|
154
|
+
) as unknown as PreactDebouncer<TFn, TSelected>
|
|
155
|
+
|
|
156
|
+
debouncerInstance.Subscribe = function Subscribe<TSelected>(props: {
|
|
157
|
+
selector: (state: DebouncerState<TFn>) => TSelected
|
|
158
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
159
|
+
}) {
|
|
160
|
+
const selected = useStore(debouncerInstance.store, props.selector)
|
|
161
|
+
|
|
162
|
+
return typeof props.children === 'function'
|
|
163
|
+
? props.children(selected)
|
|
164
|
+
: props.children
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return debouncerInstance
|
|
168
|
+
})
|
|
116
169
|
|
|
117
170
|
debouncer.fn = fn
|
|
118
171
|
debouncer.setOptions(mergedOptions)
|
package/src/queuer/useQueuer.ts
CHANGED
|
@@ -4,11 +4,29 @@ import { useStore } from '@tanstack/preact-store'
|
|
|
4
4
|
import { useDefaultPacerOptions } from '../provider/PacerProvider'
|
|
5
5
|
import type { Store } from '@tanstack/preact-store'
|
|
6
6
|
import type { QueuerOptions, QueuerState } from '@tanstack/pacer/queuer'
|
|
7
|
+
import type { ComponentChildren } from 'preact'
|
|
7
8
|
|
|
8
9
|
export interface PreactQueuer<TValue, TSelected = {}> extends Omit<
|
|
9
10
|
Queuer<TValue>,
|
|
10
11
|
'store'
|
|
11
12
|
> {
|
|
13
|
+
/**
|
|
14
|
+
* A Preact HOC (Higher Order Component) that allows you to subscribe to the queuer state.
|
|
15
|
+
*
|
|
16
|
+
* This is useful for opting into state re-renders for specific parts of the queuer state
|
|
17
|
+
* deep in your component tree without needing to pass a selector to the hook.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <queuer.Subscribe selector={(state) => ({ size: state.size })}>
|
|
21
|
+
* {({ size }) => (
|
|
22
|
+
* <div>Queue Size: {size}</div>
|
|
23
|
+
* )}
|
|
24
|
+
* </queuer.Subscribe>
|
|
25
|
+
*/
|
|
26
|
+
Subscribe: <TSelected>(props: {
|
|
27
|
+
selector: (state: QueuerState<TValue>) => TSelected
|
|
28
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
29
|
+
}) => ComponentChildren
|
|
12
30
|
/**
|
|
13
31
|
* Reactive state that will be updated and re-rendered when the queuer state changes
|
|
14
32
|
*
|
|
@@ -42,14 +60,24 @@ export interface PreactQueuer<TValue, TSelected = {}> extends Omit<
|
|
|
42
60
|
*
|
|
43
61
|
* ## State Management and Selector
|
|
44
62
|
*
|
|
45
|
-
* The hook uses TanStack Store for reactive state management.
|
|
46
|
-
*
|
|
47
|
-
*
|
|
63
|
+
* The hook uses TanStack Store for reactive state management. You can subscribe to state changes
|
|
64
|
+
* in two ways:
|
|
65
|
+
*
|
|
66
|
+
* **1. Using `queuer.Subscribe` HOC (Recommended for component tree subscriptions)**
|
|
67
|
+
*
|
|
68
|
+
* Use the `Subscribe` HOC to subscribe to state changes deep in your component tree without
|
|
69
|
+
* needing to pass a selector to the hook. This is ideal when you want to subscribe to state
|
|
70
|
+
* in child components.
|
|
71
|
+
*
|
|
72
|
+
* **2. Using the `selector` parameter (For hook-level subscriptions)**
|
|
73
|
+
*
|
|
74
|
+
* The `selector` parameter allows you to specify which state changes will trigger a re-render
|
|
75
|
+
* at the hook level, optimizing performance by preventing unnecessary re-renders when irrelevant
|
|
76
|
+
* state changes occur.
|
|
48
77
|
*
|
|
49
78
|
* **By default, there will be no reactive state subscriptions** and you must opt-in to state
|
|
50
|
-
* tracking by providing a selector function. This prevents unnecessary
|
|
51
|
-
* full control over when your component updates.
|
|
52
|
-
* component re-render when the selected state values change.
|
|
79
|
+
* tracking by providing a selector function or using the `Subscribe` HOC. This prevents unnecessary
|
|
80
|
+
* re-renders and gives you full control over when your component updates.
|
|
53
81
|
*
|
|
54
82
|
* Available state properties:
|
|
55
83
|
* - `executionCount`: Number of items that have been processed by the queuer
|
|
@@ -73,7 +101,14 @@ export interface PreactQueuer<TValue, TSelected = {}> extends Omit<
|
|
|
73
101
|
* { started: true, wait: 1000 }
|
|
74
102
|
* );
|
|
75
103
|
*
|
|
76
|
-
* //
|
|
104
|
+
* // Subscribe to state changes deep in component tree using Subscribe HOC
|
|
105
|
+
* <queue.Subscribe selector={(state) => ({ size: state.size })}>
|
|
106
|
+
* {({ size }) => (
|
|
107
|
+
* <div>Queue Size: {size}</div>
|
|
108
|
+
* )}
|
|
109
|
+
* </queue.Subscribe>
|
|
110
|
+
*
|
|
111
|
+
* // Opt-in to re-render when queue size changes at hook level (optimized for displaying queue length)
|
|
77
112
|
* const queue = useQueuer(
|
|
78
113
|
* (item) => console.log('Processing:', item),
|
|
79
114
|
* { started: true, wait: 1000 },
|
|
@@ -142,7 +177,25 @@ export function useQueuer<TValue, TSelected = {}>(
|
|
|
142
177
|
...options,
|
|
143
178
|
} as QueuerOptions<TValue>
|
|
144
179
|
|
|
145
|
-
const [queuer] = useState(() =>
|
|
180
|
+
const [queuer] = useState(() => {
|
|
181
|
+
const queuerInstance = new Queuer<TValue>(
|
|
182
|
+
fn,
|
|
183
|
+
mergedOptions,
|
|
184
|
+
) as unknown as PreactQueuer<TValue, TSelected>
|
|
185
|
+
|
|
186
|
+
queuerInstance.Subscribe = function Subscribe<TSelected>(props: {
|
|
187
|
+
selector: (state: QueuerState<TValue>) => TSelected
|
|
188
|
+
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
|
|
189
|
+
}) {
|
|
190
|
+
const selected = useStore(queuerInstance.store, props.selector)
|
|
191
|
+
|
|
192
|
+
return typeof props.children === 'function'
|
|
193
|
+
? props.children(selected)
|
|
194
|
+
: props.children
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return queuerInstance
|
|
198
|
+
})
|
|
146
199
|
|
|
147
200
|
queuer.fn = fn
|
|
148
201
|
queuer.setOptions(mergedOptions)
|