@octanejs/tanstack-pacer 0.0.5
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/LICENSE +21 -0
- package/README.md +9 -0
- package/package.json +62 -0
- package/src/async-batcher/index.ts +5 -0
- package/src/async-batcher/useAsyncBatchedCallback.ts +20 -0
- package/src/async-batcher/useAsyncBatcher.ts +116 -0
- package/src/async-debouncer/index.ts +5 -0
- package/src/async-debouncer/useAsyncDebouncedCallback.ts +25 -0
- package/src/async-debouncer/useAsyncDebouncer.ts +123 -0
- package/src/async-queuer/index.ts +5 -0
- package/src/async-queuer/useAsyncQueuedState.ts +30 -0
- package/src/async-queuer/useAsyncQueuer.ts +116 -0
- package/src/async-rate-limiter/index.ts +5 -0
- package/src/async-rate-limiter/useAsyncRateLimitedCallback.ts +27 -0
- package/src/async-rate-limiter/useAsyncRateLimiter.ts +120 -0
- package/src/async-retryer/index.ts +1 -0
- package/src/async-throttler/index.ts +5 -0
- package/src/async-throttler/useAsyncThrottledCallback.ts +24 -0
- package/src/async-throttler/useAsyncThrottler.ts +116 -0
- package/src/batcher/index.ts +5 -0
- package/src/batcher/useBatchedCallback.ts +20 -0
- package/src/batcher/useBatcher.ts +108 -0
- package/src/debouncer/index.ts +7 -0
- package/src/debouncer/useDebouncedCallback.ts +22 -0
- package/src/debouncer/useDebouncedState.ts +37 -0
- package/src/debouncer/useDebouncedValue.ts +41 -0
- package/src/debouncer/useDebouncer.ts +122 -0
- package/src/index.ts +63 -0
- package/src/internal.ts +45 -0
- package/src/provider/PacerProvider.tsrx +25 -0
- package/src/provider/PacerProvider.tsrx.d.ts +12 -0
- package/src/provider/context.ts +43 -0
- package/src/provider/index.ts +4 -0
- package/src/queuer/index.ts +6 -0
- package/src/queuer/useQueuedState.ts +27 -0
- package/src/queuer/useQueuedValue.ts +37 -0
- package/src/queuer/useQueuer.ts +110 -0
- package/src/rate-limiter/index.ts +7 -0
- package/src/rate-limiter/useRateLimitedCallback.ts +24 -0
- package/src/rate-limiter/useRateLimitedState.ts +34 -0
- package/src/rate-limiter/useRateLimitedValue.ts +38 -0
- package/src/rate-limiter/useRateLimiter.ts +119 -0
- package/src/throttler/index.ts +7 -0
- package/src/throttler/useThrottledCallback.ts +20 -0
- package/src/throttler/useThrottledState.ts +35 -0
- package/src/throttler/useThrottledValue.ts +38 -0
- package/src/throttler/useThrottler.ts +119 -0
- package/src/types/index.ts +1 -0
- package/src/utils/index.ts +1 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useEffect } from 'octane';
|
|
2
|
+
import { useThrottledState } from './useThrottledState';
|
|
3
|
+
import type { ReactThrottler, ReactThrottlerOptions } from './useThrottler';
|
|
4
|
+
import type { Dispatch, SetStateAction } from '../internal';
|
|
5
|
+
import type { ThrottlerState } from '@tanstack/pacer/throttler';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* An Octane hook that creates a throttled value that updates at most once per
|
|
9
|
+
* wait period. Automatically tracks changes to the input value.
|
|
10
|
+
*
|
|
11
|
+
* **By default there are no reactive state subscriptions** — opt in by
|
|
12
|
+
* providing a `selector` (see {@link useThrottler}).
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* const [throttledValue, throttler] = useThrottledValue(value, { wait: 1000 });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function useThrottledValue<
|
|
20
|
+
TValue,
|
|
21
|
+
TSelected = ThrottlerState<Dispatch<SetStateAction<TValue>>>,
|
|
22
|
+
>(
|
|
23
|
+
value: TValue,
|
|
24
|
+
options: ReactThrottlerOptions<Dispatch<SetStateAction<TValue>>, TSelected>,
|
|
25
|
+
selector?: (state: ThrottlerState<Dispatch<SetStateAction<TValue>>>) => TSelected,
|
|
26
|
+
): [TValue, ReactThrottler<Dispatch<SetStateAction<TValue>>, TSelected>] {
|
|
27
|
+
const [throttledValue, setThrottledValue, throttler] = useThrottledState(
|
|
28
|
+
value,
|
|
29
|
+
options,
|
|
30
|
+
selector,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
setThrottledValue(value);
|
|
35
|
+
}, [value, setThrottledValue]);
|
|
36
|
+
|
|
37
|
+
return [throttledValue, throttler];
|
|
38
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from 'octane';
|
|
2
|
+
import { Throttler } from '@tanstack/pacer/throttler';
|
|
3
|
+
import { shallow } from '@octanejs/tanstack-store';
|
|
4
|
+
import { useDefaultPacerOptions } from '../provider/context';
|
|
5
|
+
import { useSelectorSlot } from '../internal';
|
|
6
|
+
import type { Store } from '@octanejs/tanstack-store';
|
|
7
|
+
import type { ThrottlerOptions, ThrottlerState } from '@tanstack/pacer/throttler';
|
|
8
|
+
import type { AnyFunction } from '@tanstack/pacer/types';
|
|
9
|
+
|
|
10
|
+
const subscribeSlot = Symbol.for('@octanejs/tanstack-pacer:useThrottler:Subscribe');
|
|
11
|
+
const stateSlot = Symbol.for('@octanejs/tanstack-pacer:useThrottler:state');
|
|
12
|
+
|
|
13
|
+
export interface ReactThrottlerOptions<
|
|
14
|
+
TFn extends AnyFunction,
|
|
15
|
+
TSelected = {},
|
|
16
|
+
> extends ThrottlerOptions<TFn> {
|
|
17
|
+
/**
|
|
18
|
+
* Custom unmount behavior. Defaults to cancelling any pending execution.
|
|
19
|
+
*/
|
|
20
|
+
onUnmount?: (throttler: ReactThrottler<TFn, TSelected>) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ReactThrottler<TFn extends AnyFunction, TSelected = {}> extends Omit<
|
|
24
|
+
Throttler<TFn>,
|
|
25
|
+
'store'
|
|
26
|
+
> {
|
|
27
|
+
/**
|
|
28
|
+
* Render-prop component subscribing to a slice of the throttler's state.
|
|
29
|
+
*/
|
|
30
|
+
Subscribe: <TSelected>(props: {
|
|
31
|
+
selector: (state: ThrottlerState<TFn>) => TSelected;
|
|
32
|
+
children: ((state: TSelected) => unknown) | unknown;
|
|
33
|
+
}) => unknown;
|
|
34
|
+
/**
|
|
35
|
+
* Reactive state selected by the hook's `selector` (empty object without one).
|
|
36
|
+
*/
|
|
37
|
+
readonly state: Readonly<TSelected>;
|
|
38
|
+
/**
|
|
39
|
+
* The underlying TanStack Store instance.
|
|
40
|
+
*/
|
|
41
|
+
readonly store: Store<Readonly<ThrottlerState<TFn>>>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* An Octane hook that creates and manages a Throttler instance.
|
|
46
|
+
*
|
|
47
|
+
* The throttler limits how often a function can execute, ensuring executions
|
|
48
|
+
* are spaced by at least the specified wait time.
|
|
49
|
+
*
|
|
50
|
+
* **By default there are no reactive state subscriptions** — opt in by
|
|
51
|
+
* providing a `selector`; only then does the component re-render when the
|
|
52
|
+
* selected state values change.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* const throttler = useThrottler(updateValue, { wait: 1000 }, (state) => ({
|
|
57
|
+
* executionCount: state.executionCount,
|
|
58
|
+
* }));
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function useThrottler<TFn extends AnyFunction, TSelected = {}>(
|
|
62
|
+
fn: TFn,
|
|
63
|
+
options: ReactThrottlerOptions<TFn, TSelected>,
|
|
64
|
+
selector: (state: ThrottlerState<TFn>) => TSelected = () => ({}) as TSelected,
|
|
65
|
+
): ReactThrottler<TFn, TSelected> {
|
|
66
|
+
const mergedOptions = {
|
|
67
|
+
...useDefaultPacerOptions().throttler,
|
|
68
|
+
...options,
|
|
69
|
+
} as ReactThrottlerOptions<TFn, TSelected>;
|
|
70
|
+
const [throttler] = useState(() => {
|
|
71
|
+
const throttlerInstance = new Throttler<TFn>(fn, mergedOptions) as unknown as ReactThrottler<
|
|
72
|
+
TFn,
|
|
73
|
+
TSelected
|
|
74
|
+
>;
|
|
75
|
+
|
|
76
|
+
throttlerInstance.Subscribe = function Subscribe<TSelected>(props: {
|
|
77
|
+
selector: (state: ThrottlerState<TFn>) => TSelected;
|
|
78
|
+
children: ((state: TSelected) => unknown) | unknown;
|
|
79
|
+
}) {
|
|
80
|
+
const selected = useSelectorSlot(
|
|
81
|
+
throttlerInstance.store,
|
|
82
|
+
props.selector,
|
|
83
|
+
{ compare: shallow },
|
|
84
|
+
subscribeSlot,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return typeof props.children === 'function'
|
|
88
|
+
? (props.children as (state: TSelected) => unknown)(selected)
|
|
89
|
+
: props.children;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return throttlerInstance;
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
throttler.fn = fn;
|
|
96
|
+
throttler.setOptions(mergedOptions);
|
|
97
|
+
|
|
98
|
+
const state = useSelectorSlot(throttler.store, selector, { compare: shallow }, stateSlot);
|
|
99
|
+
|
|
100
|
+
// Unmount cleanup only; empty deps keep teardown stable (as upstream).
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
return () => {
|
|
103
|
+
if (mergedOptions.onUnmount) {
|
|
104
|
+
mergedOptions.onUnmount(throttler);
|
|
105
|
+
} else {
|
|
106
|
+
throttler.cancel();
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}, []);
|
|
110
|
+
|
|
111
|
+
return useMemo(
|
|
112
|
+
() =>
|
|
113
|
+
({
|
|
114
|
+
...throttler,
|
|
115
|
+
state,
|
|
116
|
+
}) as ReactThrottler<TFn, TSelected>, // omit `store` in favor of `state`
|
|
117
|
+
[throttler, state],
|
|
118
|
+
);
|
|
119
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@tanstack/pacer/types';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@tanstack/pacer/utils';
|