@aweebit/react-essentials 0.8.0 → 0.8.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/LICENSE +0 -2
- package/README.md +53 -69
- package/dist/hooks/useEventListener.d.ts +10 -9
- package/dist/hooks/useEventListener.d.ts.map +1 -1
- package/dist/hooks/useEventListener.js +3 -7
- package/dist/hooks/useEventListener.js.map +1 -1
- package/dist/hooks/useForceUpdate.d.ts +4 -48
- package/dist/hooks/useForceUpdate.d.ts.map +1 -1
- package/dist/hooks/useForceUpdate.js +4 -48
- package/dist/hooks/useForceUpdate.js.map +1 -1
- package/dist/hooks/useReducerWithDeps.d.ts +7 -0
- package/dist/hooks/useReducerWithDeps.d.ts.map +1 -1
- package/dist/hooks/useReducerWithDeps.js +10 -3
- package/dist/hooks/useReducerWithDeps.js.map +1 -1
- package/dist/hooks/useStateWithDeps.d.ts +6 -7
- package/dist/hooks/useStateWithDeps.d.ts.map +1 -1
- package/dist/hooks/useStateWithDeps.js +14 -45
- package/dist/hooks/useStateWithDeps.js.map +1 -1
- package/dist/utils.d.ts +0 -3
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +0 -4
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/hooks/useEventListener.ts +19 -15
- package/src/hooks/useForceUpdate.ts +4 -48
- package/src/hooks/useReducerWithDeps.ts +10 -3
- package/src/hooks/useStateWithDeps.ts +14 -48
- package/src/utils.ts +0 -8
package/LICENSE
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
3
|
Copyright (c) 2025 Wee Bit
|
|
4
|
-
Portions Copyright (c) 2020 Peter Juras
|
|
5
|
-
Portions Copyright (c) 2020 Julien CARON
|
|
6
4
|
|
|
7
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
const useEventListener: UseEventListener;
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
Defined in: [hooks/useEventListener.ts:
|
|
35
|
+
Defined in: [hooks/useEventListener.ts:135](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useEventListener.ts#L135)
|
|
36
36
|
|
|
37
37
|
Adds `handler` as a listener for the event `eventName` of `target` with the
|
|
38
38
|
provided `options` applied
|
|
@@ -73,68 +73,24 @@ useEventListener(buttonRef, 'click', () => console.log('click'));
|
|
|
73
73
|
|
|
74
74
|
---
|
|
75
75
|
|
|
76
|
-
## useForceUpdate()
|
|
76
|
+
## ~~useForceUpdate()~~
|
|
77
77
|
|
|
78
78
|
```ts
|
|
79
79
|
function useForceUpdate(callback?): [() => void, bigint];
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
Defined in: [hooks/useForceUpdate.ts:
|
|
82
|
+
Defined in: [hooks/useForceUpdate.ts:37](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useForceUpdate.ts#L37)
|
|
83
83
|
|
|
84
84
|
Enables you to imperatively trigger re-rendering of components
|
|
85
85
|
|
|
86
86
|
This hook is designed in the most general way possible in order to cover all
|
|
87
87
|
imaginable use cases.
|
|
88
88
|
|
|
89
|
-
###
|
|
90
|
-
|
|
91
|
-
Sometimes, React's immutability constraints mean too much unnecessary copying
|
|
92
|
-
of data when new data arrives at a high frequency. In such cases, it might be
|
|
93
|
-
desirable to ignore the constraints by embracing imperative patterns.
|
|
94
|
-
Here is an example of a scenario where that can make sense:
|
|
89
|
+
### Deprecated
|
|
95
90
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const mostRecentSensorDataTimestampRef = useRef<number>(0);
|
|
100
|
-
|
|
101
|
-
const [forceUpdate, updateCount] = useForceUpdate();
|
|
102
|
-
// Limiting the frequency of forced re-renders with some throttle function:
|
|
103
|
-
const throttledForceUpdateRef = useRef(throttle(forceUpdate));
|
|
104
|
-
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
return sensorDataObservable.subscribe((data: SensorData) => {
|
|
107
|
-
// Imagine new sensor data arrives every 1 millisecond. If we were following
|
|
108
|
-
// React's immutability rules by creating a new array every time, the data
|
|
109
|
-
// that's already there would have to be copied many times before the new
|
|
110
|
-
// data would even get a chance to be reflected in the UI for the first time
|
|
111
|
-
// because it typically takes much longer than 1 millisecond for a new frame
|
|
112
|
-
// to be displayed. To prevent the waste of computational resources, we just
|
|
113
|
-
// mutate the existing array every time instead:
|
|
114
|
-
sensorDataRef.current.push(data);
|
|
115
|
-
if (data.timestamp > mostRecentSensorDataTimestampRef.current) {
|
|
116
|
-
mostRecentSensorDataTimestampRef.current = data.timestamp;
|
|
117
|
-
}
|
|
118
|
-
throttledForceUpdateRef.current();
|
|
119
|
-
});
|
|
120
|
-
}, []);
|
|
121
|
-
|
|
122
|
-
const [timeWindow, setTimeWindow] = useState(1000);
|
|
123
|
-
const selectedSensorData = useMemo(
|
|
124
|
-
() => {
|
|
125
|
-
// Keep this line if you don't want to disable the
|
|
126
|
-
// react-hooks/exhaustive-deps ESLint rule:
|
|
127
|
-
updateCount;
|
|
128
|
-
const threshold = mostRecentSensorDataTimestampRef.current - timeWindow;
|
|
129
|
-
return sensorDataRef.current.filter(
|
|
130
|
-
({ timestamp }) => timestamp >= threshold,
|
|
131
|
-
);
|
|
132
|
-
},
|
|
133
|
-
// sensorDataRef.current always references the same array, so listing it as a
|
|
134
|
-
// dependency is pointless. Instead, updateCount should be used:
|
|
135
|
-
[updateCount, timeWindow],
|
|
136
|
-
);
|
|
137
|
-
```
|
|
91
|
+
This hook encourages patterns that are unsafe in Concurrent React.
|
|
92
|
+
For details and ideas on how to get rid of it, please check the discussion at
|
|
93
|
+
https://www.reddit.com/r/react/comments/1nqcsri/comment/ng76cv5/.
|
|
138
94
|
|
|
139
95
|
### Parameters
|
|
140
96
|
|
|
@@ -199,11 +155,18 @@ function useReducerWithDeps<S, A>(
|
|
|
199
155
|
): [S, ActionDispatch<A>];
|
|
200
156
|
```
|
|
201
157
|
|
|
202
|
-
Defined in: [hooks/useReducerWithDeps.ts:
|
|
158
|
+
Defined in: [hooks/useReducerWithDeps.ts:59](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useReducerWithDeps.ts#L59)
|
|
203
159
|
|
|
204
160
|
`useReducer` hook with an additional dependency array `deps` that resets the
|
|
205
161
|
state to `initialState` when dependencies change
|
|
206
162
|
|
|
163
|
+
This hook is the reducer pattern counterpart of [`useStateWithDeps`](#usestatewithdeps).
|
|
164
|
+
|
|
165
|
+
Due to React's limitations, a change in dependencies always causes two
|
|
166
|
+
renders when using this hook. The result of the first render is thrown away
|
|
167
|
+
as described in
|
|
168
|
+
[useState > Storing information from previous renders](https://react.dev/reference/react/useState#storing-information-from-previous-renders).
|
|
169
|
+
|
|
207
170
|
For motivation and examples, see
|
|
208
171
|
https://github.com/facebook/react/issues/33041.
|
|
209
172
|
|
|
@@ -335,11 +298,16 @@ function useStateWithDeps<S>(
|
|
|
335
298
|
): [S, Dispatch<SetStateAction<S>>];
|
|
336
299
|
```
|
|
337
300
|
|
|
338
|
-
Defined in: [hooks/useStateWithDeps.ts:
|
|
301
|
+
Defined in: [hooks/useStateWithDeps.ts:62](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useStateWithDeps.ts#L62)
|
|
339
302
|
|
|
340
303
|
`useState` hook with an additional dependency array `deps` that resets the
|
|
341
304
|
state to `initialState` when dependencies change
|
|
342
305
|
|
|
306
|
+
Due to React's limitations, a change in dependencies always causes two
|
|
307
|
+
renders when using this hook. The result of the first render is thrown away
|
|
308
|
+
as described in
|
|
309
|
+
[useState > Storing information from previous renders](https://react.dev/reference/react/useState#storing-information-from-previous-renders).
|
|
310
|
+
|
|
343
311
|
For motivation and more examples, see
|
|
344
312
|
https://github.com/facebook/react/issues/33041.
|
|
345
313
|
|
|
@@ -359,7 +327,7 @@ const activityOptionsByTimeOfDay: {
|
|
|
359
327
|
evening: ['board games', 'dinner'],
|
|
360
328
|
};
|
|
361
329
|
|
|
362
|
-
|
|
330
|
+
function Example() {
|
|
363
331
|
const [timeOfDay, setTimeOfDay] = useState<TimeOfDay>('morning');
|
|
364
332
|
|
|
365
333
|
const activityOptions = activityOptionsByTimeOfDay[timeOfDay];
|
|
@@ -462,7 +430,7 @@ function createSafeContext<T>(): <DisplayName>(
|
|
|
462
430
|
) => SafeContext<DisplayName, T>;
|
|
463
431
|
```
|
|
464
432
|
|
|
465
|
-
Defined in: [misc/createSafeContext.ts:95](https://github.com/aweebit/react-essentials/blob/v0.8.
|
|
433
|
+
Defined in: [misc/createSafeContext.ts:95](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/misc/createSafeContext.ts#L95)
|
|
466
434
|
|
|
467
435
|
For a given type `T`, returns a function that produces both a context of that
|
|
468
436
|
type and a hook that returns the current context value if one was provided,
|
|
@@ -609,15 +577,11 @@ A function that accepts a single string argument `displayName` (e.g.
|
|
|
609
577
|
|
|
610
578
|
```ts
|
|
611
579
|
type UseEventListener = UseEventListenerWithImplicitWindowTarget &
|
|
612
|
-
|
|
613
|
-
UseEventListenerWithExplicitTarget<Document, DocumentEventMap> &
|
|
614
|
-
UseEventListenerWithExplicitTarget<HTMLElement, HTMLElementEventMap> &
|
|
615
|
-
UseEventListenerWithExplicitTarget<SVGElement, SVGElementEventMap> &
|
|
616
|
-
UseEventListenerWithExplicitTarget<MathMLElement, MathMLElementEventMap> &
|
|
580
|
+
UseEventListenerWithExplicitGlobalTarget &
|
|
617
581
|
UseEventListenerWithAnyExplicitTarget;
|
|
618
582
|
```
|
|
619
583
|
|
|
620
|
-
Defined in: [hooks/useEventListener.ts:
|
|
584
|
+
Defined in: [hooks/useEventListener.ts:12](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useEventListener.ts#L12)
|
|
621
585
|
|
|
622
586
|
The type of [`useEventListener`](#useeventlistener-1)
|
|
623
587
|
|
|
@@ -625,7 +589,7 @@ The type of [`useEventListener`](#useeventlistener-1)
|
|
|
625
589
|
|
|
626
590
|
[`useEventListener`](#useeventlistener-1),
|
|
627
591
|
[`UseEventListenerWithImplicitWindowTarget`](#useeventlistenerwithimplicitwindowtarget),
|
|
628
|
-
[`
|
|
592
|
+
[`UseEventListenerWithExplicitGlobalTarget`](#useeventlistenerwithexplicitglobaltarget),
|
|
629
593
|
[`UseEventListenerWithAnyExplicitTarget`](#useeventlistenerwithanyexplicittarget)
|
|
630
594
|
|
|
631
595
|
---
|
|
@@ -636,7 +600,7 @@ The type of [`useEventListener`](#useeventlistener-1)
|
|
|
636
600
|
type UseEventListenerWithImplicitWindowTarget = <K>(...args) => void;
|
|
637
601
|
```
|
|
638
602
|
|
|
639
|
-
Defined in: [hooks/useEventListener.ts:
|
|
603
|
+
Defined in: [hooks/useEventListener.ts:21](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useEventListener.ts#L21)
|
|
640
604
|
|
|
641
605
|
### Type Parameters
|
|
642
606
|
|
|
@@ -693,6 +657,26 @@ Defined in: [hooks/useEventListener.ts:31](https://github.com/aweebit/react-esse
|
|
|
693
657
|
|
|
694
658
|
---
|
|
695
659
|
|
|
660
|
+
## UseEventListenerWithExplicitGlobalTarget
|
|
661
|
+
|
|
662
|
+
```ts
|
|
663
|
+
type UseEventListenerWithExplicitGlobalTarget =
|
|
664
|
+
UseEventListenerWithExplicitTarget<Window, WindowEventMap> &
|
|
665
|
+
UseEventListenerWithExplicitTarget<Document, DocumentEventMap> &
|
|
666
|
+
UseEventListenerWithExplicitTarget<HTMLElement, HTMLElementEventMap> &
|
|
667
|
+
UseEventListenerWithExplicitTarget<SVGElement, SVGElementEventMap> &
|
|
668
|
+
UseEventListenerWithExplicitTarget<MathMLElement, MathMLElementEventMap>;
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
Defined in: [hooks/useEventListener.ts:32](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useEventListener.ts#L32)
|
|
672
|
+
|
|
673
|
+
### See
|
|
674
|
+
|
|
675
|
+
[`useEventListener`](#useeventlistener-1),
|
|
676
|
+
[`UseEventListenerWithExplicitTarget`](#useeventlistenerwithexplicittarget)
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
696
680
|
## UseEventListenerWithExplicitTarget()
|
|
697
681
|
|
|
698
682
|
```ts
|
|
@@ -701,7 +685,7 @@ type UseEventListenerWithExplicitTarget<Target, EventMap> = <T, K>(
|
|
|
701
685
|
) => void;
|
|
702
686
|
```
|
|
703
687
|
|
|
704
|
-
Defined in: [hooks/useEventListener.ts:
|
|
688
|
+
Defined in: [hooks/useEventListener.ts:44](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useEventListener.ts#L44)
|
|
705
689
|
|
|
706
690
|
### Type Parameters
|
|
707
691
|
|
|
@@ -809,7 +793,7 @@ type UseEventListenerWithAnyExplicitTarget =
|
|
|
809
793
|
UseEventListenerWithExplicitTarget<EventTarget>;
|
|
810
794
|
```
|
|
811
795
|
|
|
812
|
-
Defined in: [hooks/useEventListener.ts:
|
|
796
|
+
Defined in: [hooks/useEventListener.ts:56](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useEventListener.ts#L56)
|
|
813
797
|
|
|
814
798
|
### See
|
|
815
799
|
|
|
@@ -830,7 +814,7 @@ type UseEventListenerWithImplicitWindowTargetArgs<K> =
|
|
|
830
814
|
: never;
|
|
831
815
|
```
|
|
832
816
|
|
|
833
|
-
Defined in: [hooks/useEventListener.ts:
|
|
817
|
+
Defined in: [hooks/useEventListener.ts:64](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useEventListener.ts#L64)
|
|
834
818
|
|
|
835
819
|
### Type Parameters
|
|
836
820
|
|
|
@@ -875,7 +859,7 @@ type UseEventListenerWithExplicitTargetArgs<EventMap, T, K> = [
|
|
|
875
859
|
];
|
|
876
860
|
```
|
|
877
861
|
|
|
878
|
-
Defined in: [hooks/useEventListener.ts:
|
|
862
|
+
Defined in: [hooks/useEventListener.ts:78](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/hooks/useEventListener.ts#L78)
|
|
879
863
|
|
|
880
864
|
### Type Parameters
|
|
881
865
|
|
|
@@ -931,7 +915,7 @@ type RestrictedContext<T> =
|
|
|
931
915
|
};
|
|
932
916
|
```
|
|
933
917
|
|
|
934
|
-
Defined in: [misc/createSafeContext.ts:18](https://github.com/aweebit/react-essentials/blob/v0.8.
|
|
918
|
+
Defined in: [misc/createSafeContext.ts:18](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/misc/createSafeContext.ts#L18)
|
|
935
919
|
|
|
936
920
|
A React context with a required `displayName` and the obsolete `Consumer`
|
|
937
921
|
property purposefully omitted so that it is impossible to pass the context
|
|
@@ -971,7 +955,7 @@ type SafeContext<DisplayName, T> = {
|
|
|
971
955
|
} & { [K in `use${DisplayName}`]: () => T };
|
|
972
956
|
```
|
|
973
957
|
|
|
974
|
-
Defined in: [misc/createSafeContext.ts:30](https://github.com/aweebit/react-essentials/blob/v0.8.
|
|
958
|
+
Defined in: [misc/createSafeContext.ts:30](https://github.com/aweebit/react-essentials/blob/v0.8.1/src/misc/createSafeContext.ts#L30)
|
|
975
959
|
|
|
976
960
|
The return type of [`createSafeContext`](#createsafecontext)
|
|
977
961
|
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Based on {@link https://github.com/juliencrn/usehooks-ts}
|
|
3
|
-
*
|
|
4
|
-
* @license MIT
|
|
5
|
-
* @copyright 2020 Julien CARON
|
|
6
|
-
*/
|
|
7
1
|
import { type RefObject } from 'react';
|
|
8
2
|
/**
|
|
9
3
|
* The type of {@linkcode useEventListener}
|
|
@@ -11,15 +5,22 @@ import { type RefObject } from 'react';
|
|
|
11
5
|
* @see
|
|
12
6
|
* {@linkcode useEventListener},
|
|
13
7
|
* {@linkcode UseEventListenerWithImplicitWindowTarget},
|
|
14
|
-
* {@linkcode
|
|
8
|
+
* {@linkcode UseEventListenerWithExplicitGlobalTarget},
|
|
15
9
|
* {@linkcode UseEventListenerWithAnyExplicitTarget}
|
|
16
10
|
*/
|
|
17
|
-
export type UseEventListener = UseEventListenerWithImplicitWindowTarget &
|
|
11
|
+
export type UseEventListener = UseEventListenerWithImplicitWindowTarget & UseEventListenerWithExplicitGlobalTarget & UseEventListenerWithAnyExplicitTarget;
|
|
18
12
|
/**
|
|
19
13
|
* @see
|
|
20
14
|
* {@linkcode useEventListener},
|
|
21
|
-
* {@linkcode UseEventListenerWithImplicitWindowTargetArgs}
|
|
15
|
+
* {@linkcode UseEventListenerWithImplicitWindowTargetArgs}
|
|
16
|
+
*/
|
|
22
17
|
export type UseEventListenerWithImplicitWindowTarget = <K extends keyof WindowEventMap>(...args: UseEventListenerWithImplicitWindowTargetArgs<K>) => void;
|
|
18
|
+
/**
|
|
19
|
+
* @see
|
|
20
|
+
* {@linkcode useEventListener},
|
|
21
|
+
* {@linkcode UseEventListenerWithExplicitTarget}
|
|
22
|
+
*/
|
|
23
|
+
export type UseEventListenerWithExplicitGlobalTarget = UseEventListenerWithExplicitTarget<Window, WindowEventMap> & UseEventListenerWithExplicitTarget<Document, DocumentEventMap> & UseEventListenerWithExplicitTarget<HTMLElement, HTMLElementEventMap> & UseEventListenerWithExplicitTarget<SVGElement, SVGElementEventMap> & UseEventListenerWithExplicitTarget<MathMLElement, MathMLElementEventMap>;
|
|
23
24
|
/**
|
|
24
25
|
* @see
|
|
25
26
|
* {@linkcode useEventListener},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEventListener.d.ts","sourceRoot":"","sources":["../../src/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"useEventListener.d.ts","sourceRoot":"","sources":["../../src/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,wCAAwC,GACrE,wCAAwC,GACxC,qCAAqC,CAAC;AAExC;;;;GAIG;AACH,MAAM,MAAM,wCAAwC,GAAG,CACrD,CAAC,SAAS,MAAM,cAAc,EAE9B,GAAG,IAAI,EAAE,4CAA4C,CAAC,CAAC,CAAC,KACrD,IAAI,CAAC;AAEV;;;;GAIG;AACH,MAAM,MAAM,wCAAwC,GAClD,kCAAkC,CAAC,MAAM,EAAE,cAAc,CAAC,GACxD,kCAAkC,CAAC,QAAQ,EAAE,gBAAgB,CAAC,GAC9D,kCAAkC,CAAC,WAAW,EAAE,mBAAmB,CAAC,GACpE,kCAAkC,CAAC,UAAU,EAAE,kBAAkB,CAAC,GAClE,kCAAkC,CAAC,aAAa,EAAE,qBAAqB,CAAC,CAAC;AAE7E;;;;GAIG;AACH,MAAM,MAAM,kCAAkC,CAC5C,MAAM,SAAS,WAAW,EAC1B,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAC9B,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,QAAQ,EAC7C,GAAG,IAAI,EAAE,sCAAsC,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,KAC5D,IAAI,CAAC;AAEV;;;;GAIG;AACH,MAAM,MAAM,qCAAqC,GAC/C,kCAAkC,CAAC,WAAW,CAAC,CAAC;AAElD;;;;GAIG;AACH,MAAM,MAAM,4CAA4C,CACtD,CAAC,SAAS,MAAM,cAAc,IAE9B,sCAAsC,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC,SAAS;IACxE,OAAO;IACP,GAAG,MAAM,IAAI;CACd,GACG,IAAI,GACJ,KAAK,CAAC;AAEZ;;;GAGG;AACH,MAAM,MAAM,sCAAsC,CAChD,QAAQ,EACR,CAAC,SAAS,WAAW,EACrB,CAAC,SAAS,MAAM,QAAQ,IACtB;IACF,MAAM,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;QAAE,gBAAgB,CAAC,EAAE,KAAK,CAAA;KAAE,CAAC,GAAG,IAAI;IAChE,SAAS,EAAE,CAAC;IACZ,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI;IACvD,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,GAAG,SAAS;CACxD,CAAC;AAYF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,gBAAgB,EAAE,gBAoDV,CAAC"}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Based on {@link https://github.com/juliencrn/usehooks-ts}
|
|
3
|
-
*
|
|
4
|
-
* @license MIT
|
|
5
|
-
* @copyright 2020 Julien CARON
|
|
6
|
-
*/
|
|
7
1
|
import { useEffect, useMemo, useRef } from 'react';
|
|
8
2
|
/**
|
|
9
3
|
* Adds `handler` as a listener for the event `eventName` of `target` with the
|
|
@@ -47,7 +41,9 @@ export const useEventListener = function useEventListener(...args) {
|
|
|
47
41
|
: args;
|
|
48
42
|
const unwrappedTarget = target && !('addEventListener' in target) ? target.current : target;
|
|
49
43
|
const handlerRef = useRef(handler);
|
|
50
|
-
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
handlerRef.current = handler;
|
|
46
|
+
}, [handler]);
|
|
51
47
|
const { capture = false, once = false, passive, signal, } = typeof options === 'boolean' ? { capture: options } : (options ?? {});
|
|
52
48
|
const memoizedOptions = useMemo(() => options,
|
|
53
49
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEventListener.js","sourceRoot":"","sources":["../../src/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"useEventListener.js","sourceRoot":"","sources":["../../src/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAC;AAkGnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAqB,SAAS,gBAAgB,CACzE,GAAG,IAE0C;IAE7C,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,GAMzC,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ;QACzB,CAAC,CAAC,CAAC,MAAM,EAAE,GAAI,IAAwD,CAAC;QACxE,CAAC,CAAE,IAAkD,CAAC;IAE1D,MAAM,eAAe,GACnB,MAAM,IAAI,CAAC,CAAC,kBAAkB,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAEtE,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;IAC/B,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,MAAM,EACJ,OAAO,GAAG,KAAK,EACf,IAAI,GAAG,KAAK,EACZ,OAAO,EACP,MAAM,GACP,GAAG,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAE1E,MAAM,eAAe,GAAG,OAAO,CAC7B,GAAG,EAAE,CAAC,OAAO;IACb,uDAAuD;IACvD,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CACjC,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;YAC7B,8CAA8C;YAC9C,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAmB,UAAU,KAAK;YAC9C,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC,CAAC;QAEF,eAAe,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;QAEvE,OAAO,GAAG,EAAE;YACV,eAAe,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;QAC5E,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC;AACpD,CAAqB,CAAC"}
|
|
@@ -4,54 +4,10 @@
|
|
|
4
4
|
* This hook is designed in the most general way possible in order to cover all
|
|
5
5
|
* imaginable use cases.
|
|
6
6
|
*
|
|
7
|
-
* @
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Here is an example of a scenario where that can make sense:
|
|
12
|
-
*
|
|
13
|
-
* ```tsx
|
|
14
|
-
* type SensorData = { timestamp: number; value: number };
|
|
15
|
-
* const sensorDataRef = useRef<SensorData[]>([]);
|
|
16
|
-
* const mostRecentSensorDataTimestampRef = useRef<number>(0);
|
|
17
|
-
*
|
|
18
|
-
* const [forceUpdate, updateCount] = useForceUpdate();
|
|
19
|
-
* // Limiting the frequency of forced re-renders with some throttle function:
|
|
20
|
-
* const throttledForceUpdateRef = useRef(throttle(forceUpdate));
|
|
21
|
-
*
|
|
22
|
-
* useEffect(() => {
|
|
23
|
-
* return sensorDataObservable.subscribe((data: SensorData) => {
|
|
24
|
-
* // Imagine new sensor data arrives every 1 millisecond. If we were following
|
|
25
|
-
* // React's immutability rules by creating a new array every time, the data
|
|
26
|
-
* // that's already there would have to be copied many times before the new
|
|
27
|
-
* // data would even get a chance to be reflected in the UI for the first time
|
|
28
|
-
* // because it typically takes much longer than 1 millisecond for a new frame
|
|
29
|
-
* // to be displayed. To prevent the waste of computational resources, we just
|
|
30
|
-
* // mutate the existing array every time instead:
|
|
31
|
-
* sensorDataRef.current.push(data);
|
|
32
|
-
* if (data.timestamp > mostRecentSensorDataTimestampRef.current) {
|
|
33
|
-
* mostRecentSensorDataTimestampRef.current = data.timestamp;
|
|
34
|
-
* }
|
|
35
|
-
* throttledForceUpdateRef.current();
|
|
36
|
-
* });
|
|
37
|
-
* }, []);
|
|
38
|
-
*
|
|
39
|
-
* const [timeWindow, setTimeWindow] = useState(1000);
|
|
40
|
-
* const selectedSensorData = useMemo(
|
|
41
|
-
* () => {
|
|
42
|
-
* // Keep this line if you don't want to disable the
|
|
43
|
-
* // react-hooks/exhaustive-deps ESLint rule:
|
|
44
|
-
* updateCount;
|
|
45
|
-
* const threshold = mostRecentSensorDataTimestampRef.current - timeWindow;
|
|
46
|
-
* return sensorDataRef.current.filter(
|
|
47
|
-
* ({ timestamp }) => timestamp >= threshold,
|
|
48
|
-
* );
|
|
49
|
-
* },
|
|
50
|
-
* // sensorDataRef.current always references the same array, so listing it as a
|
|
51
|
-
* // dependency is pointless. Instead, updateCount should be used:
|
|
52
|
-
* [updateCount, timeWindow],
|
|
53
|
-
* );
|
|
54
|
-
* ```
|
|
7
|
+
* @deprecated
|
|
8
|
+
* This hook encourages patterns that are unsafe in Concurrent React.
|
|
9
|
+
* For details and ideas on how to get rid of it, please check the discussion at
|
|
10
|
+
* https://www.reddit.com/r/react/comments/1nqcsri/comment/ng76cv5/.
|
|
55
11
|
*
|
|
56
12
|
* @param callback An optional callback function to call during renders that
|
|
57
13
|
* were triggered with `forceUpdate()`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForceUpdate.d.ts","sourceRoot":"","sources":["../../src/hooks/useForceUpdate.ts"],"names":[],"mappings":"AAOA
|
|
1
|
+
{"version":3,"file":"useForceUpdate.d.ts","sourceRoot":"","sources":["../../src/hooks/useForceUpdate.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,MAAM,CAAC,CAU1E"}
|
|
@@ -6,54 +6,10 @@ import { useReducer, useRef } from 'react';
|
|
|
6
6
|
* This hook is designed in the most general way possible in order to cover all
|
|
7
7
|
* imaginable use cases.
|
|
8
8
|
*
|
|
9
|
-
* @
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Here is an example of a scenario where that can make sense:
|
|
14
|
-
*
|
|
15
|
-
* ```tsx
|
|
16
|
-
* type SensorData = { timestamp: number; value: number };
|
|
17
|
-
* const sensorDataRef = useRef<SensorData[]>([]);
|
|
18
|
-
* const mostRecentSensorDataTimestampRef = useRef<number>(0);
|
|
19
|
-
*
|
|
20
|
-
* const [forceUpdate, updateCount] = useForceUpdate();
|
|
21
|
-
* // Limiting the frequency of forced re-renders with some throttle function:
|
|
22
|
-
* const throttledForceUpdateRef = useRef(throttle(forceUpdate));
|
|
23
|
-
*
|
|
24
|
-
* useEffect(() => {
|
|
25
|
-
* return sensorDataObservable.subscribe((data: SensorData) => {
|
|
26
|
-
* // Imagine new sensor data arrives every 1 millisecond. If we were following
|
|
27
|
-
* // React's immutability rules by creating a new array every time, the data
|
|
28
|
-
* // that's already there would have to be copied many times before the new
|
|
29
|
-
* // data would even get a chance to be reflected in the UI for the first time
|
|
30
|
-
* // because it typically takes much longer than 1 millisecond for a new frame
|
|
31
|
-
* // to be displayed. To prevent the waste of computational resources, we just
|
|
32
|
-
* // mutate the existing array every time instead:
|
|
33
|
-
* sensorDataRef.current.push(data);
|
|
34
|
-
* if (data.timestamp > mostRecentSensorDataTimestampRef.current) {
|
|
35
|
-
* mostRecentSensorDataTimestampRef.current = data.timestamp;
|
|
36
|
-
* }
|
|
37
|
-
* throttledForceUpdateRef.current();
|
|
38
|
-
* });
|
|
39
|
-
* }, []);
|
|
40
|
-
*
|
|
41
|
-
* const [timeWindow, setTimeWindow] = useState(1000);
|
|
42
|
-
* const selectedSensorData = useMemo(
|
|
43
|
-
* () => {
|
|
44
|
-
* // Keep this line if you don't want to disable the
|
|
45
|
-
* // react-hooks/exhaustive-deps ESLint rule:
|
|
46
|
-
* updateCount;
|
|
47
|
-
* const threshold = mostRecentSensorDataTimestampRef.current - timeWindow;
|
|
48
|
-
* return sensorDataRef.current.filter(
|
|
49
|
-
* ({ timestamp }) => timestamp >= threshold,
|
|
50
|
-
* );
|
|
51
|
-
* },
|
|
52
|
-
* // sensorDataRef.current always references the same array, so listing it as a
|
|
53
|
-
* // dependency is pointless. Instead, updateCount should be used:
|
|
54
|
-
* [updateCount, timeWindow],
|
|
55
|
-
* );
|
|
56
|
-
* ```
|
|
9
|
+
* @deprecated
|
|
10
|
+
* This hook encourages patterns that are unsafe in Concurrent React.
|
|
11
|
+
* For details and ideas on how to get rid of it, please check the discussion at
|
|
12
|
+
* https://www.reddit.com/r/react/comments/1nqcsri/comment/ng76cv5/.
|
|
57
13
|
*
|
|
58
14
|
* @param callback An optional callback function to call during renders that
|
|
59
15
|
* were triggered with `forceUpdate()`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForceUpdate.js","sourceRoot":"","sources":["../../src/hooks/useForceUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAK3C,mBAAmB;AAEnB
|
|
1
|
+
{"version":3,"file":"useForceUpdate.js","sourceRoot":"","sources":["../../src/hooks/useForceUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAK3C,mBAAmB;AAEnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,cAAc,CAAC,QAAqB;IAClD,6DAA6D;IAC7D,2EAA2E;IAC3E,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IACvE,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,WAAW,KAAK,cAAc,CAAC,OAAO,EAAE,CAAC;QAC3C,cAAc,CAAC,OAAO,GAAG,WAAW,CAAC;QACrC,QAAQ,EAAE,EAAE,CAAC;IACf,CAAC;IACD,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -7,6 +7,13 @@ export type ActionDispatch<ActionArg extends AnyActionArg> = (...args: ActionArg
|
|
|
7
7
|
* `useReducer` hook with an additional dependency array `deps` that resets the
|
|
8
8
|
* state to `initialState` when dependencies change
|
|
9
9
|
*
|
|
10
|
+
* This hook is the reducer pattern counterpart of {@linkcode useStateWithDeps}.
|
|
11
|
+
*
|
|
12
|
+
* Due to React's limitations, a change in dependencies always causes two
|
|
13
|
+
* renders when using this hook. The result of the first render is thrown away
|
|
14
|
+
* as described in
|
|
15
|
+
* [useState > Storing information from previous renders](https://react.dev/reference/react/useState#storing-information-from-previous-renders).
|
|
16
|
+
*
|
|
10
17
|
* For motivation and examples, see
|
|
11
18
|
* https://github.com/facebook/react/issues/33041.
|
|
12
19
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReducerWithDeps.d.ts","sourceRoot":"","sources":["../../src/hooks/useReducerWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAU,MAAM,OAAO,CAAC;AAOpD,cAAc;AAEd,MAAM,MAAM,YAAY,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtC,cAAc;AACd,MAAM,MAAM,cAAc,CAAC,SAAS,SAAS,YAAY,IAAI,CAC3D,GAAG,IAAI,EAAE,SAAS,KACf,IAAI,CAAC;AAEV
|
|
1
|
+
{"version":3,"file":"useReducerWithDeps.d.ts","sourceRoot":"","sources":["../../src/hooks/useReducerWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAU,MAAM,OAAO,CAAC;AAOpD,cAAc;AAEd,MAAM,MAAM,YAAY,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtC,cAAc;AACd,MAAM,MAAM,cAAc,CAAC,SAAS,SAAS,YAAY,IAAI,CAC3D,GAAG,IAAI,EAAE,SAAS,KACf,IAAI,CAAC;AAEV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,CAAC,SAAS,YAAY,EAC1D,OAAO,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,EACxC,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAC5C,IAAI,EAAE,cAAc,GACnB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAYxB"}
|
|
@@ -4,6 +4,13 @@ import { useStateWithDeps } from './useStateWithDeps.js';
|
|
|
4
4
|
* `useReducer` hook with an additional dependency array `deps` that resets the
|
|
5
5
|
* state to `initialState` when dependencies change
|
|
6
6
|
*
|
|
7
|
+
* This hook is the reducer pattern counterpart of {@linkcode useStateWithDeps}.
|
|
8
|
+
*
|
|
9
|
+
* Due to React's limitations, a change in dependencies always causes two
|
|
10
|
+
* renders when using this hook. The result of the first render is thrown away
|
|
11
|
+
* as described in
|
|
12
|
+
* [useState > Storing information from previous renders](https://react.dev/reference/react/useState#storing-information-from-previous-renders).
|
|
13
|
+
*
|
|
7
14
|
* For motivation and examples, see
|
|
8
15
|
* https://github.com/facebook/react/issues/33041.
|
|
9
16
|
*
|
|
@@ -40,9 +47,9 @@ export function useReducerWithDeps(reducer, initialState, deps) {
|
|
|
40
47
|
const [state, setState] = useStateWithDeps(initialState, deps);
|
|
41
48
|
// Only the initially provided reducer is used
|
|
42
49
|
const reducerRef = useRef(reducer);
|
|
43
|
-
|
|
50
|
+
function dispatch(...args) {
|
|
44
51
|
setState((previousState) => reducerRef.current(previousState, ...args));
|
|
45
|
-
}
|
|
46
|
-
return [state, dispatch];
|
|
52
|
+
}
|
|
53
|
+
return [state, useRef(dispatch).current];
|
|
47
54
|
}
|
|
48
55
|
//# sourceMappingURL=useReducerWithDeps.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReducerWithDeps.js","sourceRoot":"","sources":["../../src/hooks/useReducerWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,MAAM,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAezD
|
|
1
|
+
{"version":3,"file":"useReducerWithDeps.js","sourceRoot":"","sources":["../../src/hooks/useReducerWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,MAAM,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAezD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAwC,EACxC,YAA4C,EAC5C,IAAoB;IAEpB,uDAAuD;IACvD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAE/D,8CAA8C;IAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnC,SAAS,QAAQ,CAAC,GAAG,IAAO;QAC1B,QAAQ,CAAC,CAAC,aAAa,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Based on {@link https://github.com/peterjuras/use-state-with-deps}
|
|
3
|
-
*
|
|
4
|
-
* @license MIT
|
|
5
|
-
* @copyright 2020 Peter Juras
|
|
6
|
-
*/
|
|
7
1
|
import { type DependencyList, type Dispatch, type SetStateAction } from 'react';
|
|
8
2
|
/**
|
|
9
3
|
* `useState` hook with an additional dependency array `deps` that resets the
|
|
10
4
|
* state to `initialState` when dependencies change
|
|
11
5
|
*
|
|
6
|
+
* Due to React's limitations, a change in dependencies always causes two
|
|
7
|
+
* renders when using this hook. The result of the first render is thrown away
|
|
8
|
+
* as described in
|
|
9
|
+
* [useState > Storing information from previous renders](https://react.dev/reference/react/useState#storing-information-from-previous-renders).
|
|
10
|
+
*
|
|
12
11
|
* For motivation and more examples, see
|
|
13
12
|
* https://github.com/facebook/react/issues/33041.
|
|
14
13
|
*
|
|
@@ -27,7 +26,7 @@ import { type DependencyList, type Dispatch, type SetStateAction } from 'react';
|
|
|
27
26
|
* evening: ['board games', 'dinner'],
|
|
28
27
|
* };
|
|
29
28
|
*
|
|
30
|
-
*
|
|
29
|
+
* function Example() {
|
|
31
30
|
* const [timeOfDay, setTimeOfDay] = useState<TimeOfDay>('morning');
|
|
32
31
|
*
|
|
33
32
|
* const activityOptions = activityOptionsByTimeOfDay[timeOfDay];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStateWithDeps.d.ts","sourceRoot":"","sources":["../../src/hooks/useStateWithDeps.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"useStateWithDeps.d.ts","sourceRoot":"","sources":["../../src/hooks/useStateWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAGf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAC5C,IAAI,EAAE,cAAc,GACnB,CAAC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAWlC"}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* @license MIT
|
|
5
|
-
* @copyright 2020 Peter Juras
|
|
6
|
-
*/
|
|
7
|
-
import { useRef, } from 'react';
|
|
8
|
-
import { depsAreEqual, isFunction } from '../utils.js';
|
|
9
|
-
import { useForceUpdate } from './useForceUpdate.js';
|
|
1
|
+
import { useState, } from 'react';
|
|
2
|
+
import { depsAreEqual } from '../utils.js';
|
|
10
3
|
/**
|
|
11
4
|
* `useState` hook with an additional dependency array `deps` that resets the
|
|
12
5
|
* state to `initialState` when dependencies change
|
|
13
6
|
*
|
|
7
|
+
* Due to React's limitations, a change in dependencies always causes two
|
|
8
|
+
* renders when using this hook. The result of the first render is thrown away
|
|
9
|
+
* as described in
|
|
10
|
+
* [useState > Storing information from previous renders](https://react.dev/reference/react/useState#storing-information-from-previous-renders).
|
|
11
|
+
*
|
|
14
12
|
* For motivation and more examples, see
|
|
15
13
|
* https://github.com/facebook/react/issues/33041.
|
|
16
14
|
*
|
|
@@ -29,7 +27,7 @@ import { useForceUpdate } from './useForceUpdate.js';
|
|
|
29
27
|
* evening: ['board games', 'dinner'],
|
|
30
28
|
* };
|
|
31
29
|
*
|
|
32
|
-
*
|
|
30
|
+
* function Example() {
|
|
33
31
|
* const [timeOfDay, setTimeOfDay] = useState<TimeOfDay>('morning');
|
|
34
32
|
*
|
|
35
33
|
* const activityOptions = activityOptionsByTimeOfDay[timeOfDay];
|
|
@@ -56,41 +54,12 @@ import { useForceUpdate } from './useForceUpdate.js';
|
|
|
56
54
|
* @param deps Dependencies that reset the state to `initialState`
|
|
57
55
|
*/
|
|
58
56
|
export function useStateWithDeps(initialState, deps) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const prevDeps = useRef(deps);
|
|
65
|
-
const isMounted = useRef(false);
|
|
66
|
-
// If first render, or if dependencies have changed since last time
|
|
67
|
-
if (!isMounted.current || !depsAreEqual(prevDeps.current, deps)) {
|
|
68
|
-
// Update state and deps
|
|
69
|
-
let nextState;
|
|
70
|
-
if (isFunction(initialState)) {
|
|
71
|
-
nextState = initialState(state.current);
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
nextState = initialState;
|
|
75
|
-
}
|
|
76
|
-
state.current = nextState;
|
|
77
|
-
prevDeps.current = deps;
|
|
78
|
-
isMounted.current = true;
|
|
57
|
+
const [state, setState] = useState(initialState);
|
|
58
|
+
const [prevDeps, setPrevDeps] = useState(deps);
|
|
59
|
+
if (!depsAreEqual(deps, prevDeps)) {
|
|
60
|
+
setPrevDeps(deps);
|
|
61
|
+
setState(initialState);
|
|
79
62
|
}
|
|
80
|
-
|
|
81
|
-
const updateState = useRef(function updateState(newState) {
|
|
82
|
-
let nextState;
|
|
83
|
-
if (isFunction(newState)) {
|
|
84
|
-
nextState = newState(state.current);
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
nextState = newState;
|
|
88
|
-
}
|
|
89
|
-
if (!Object.is(state.current, nextState)) {
|
|
90
|
-
state.current = nextState;
|
|
91
|
-
forceUpdate();
|
|
92
|
-
}
|
|
93
|
-
}).current;
|
|
94
|
-
return [state.current, updateState];
|
|
63
|
+
return [state, setState];
|
|
95
64
|
}
|
|
96
65
|
//# sourceMappingURL=useStateWithDeps.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStateWithDeps.js","sourceRoot":"","sources":["../../src/hooks/useStateWithDeps.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"useStateWithDeps.js","sourceRoot":"","sources":["../../src/hooks/useStateWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,GAIT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,MAAM,UAAU,gBAAgB,CAC9B,YAA4C,EAC5C,IAAoB;IAEpB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;IAEjD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE/C,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;QAClC,WAAW,CAAC,IAAI,CAAC,CAAC;QAClB,QAAQ,CAAC,YAAY,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC3B,CAAC"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import type { DependencyList } from 'react';
|
|
2
|
-
export type Callable = (...args: never) => unknown;
|
|
3
2
|
export type ArgumentFallback<T extends Base, Default extends Base, Base = unknown> = [T] extends [never] ? Default : [Base] extends [T] ? Default : T;
|
|
4
|
-
export declare function noop(): void;
|
|
5
|
-
export declare function isFunction(input: unknown): input is Callable;
|
|
6
3
|
export declare function depsAreEqual(prevDeps: DependencyList, deps: DependencyList): boolean;
|
|
7
4
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAE5C,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAE5C,MAAM,MAAM,gBAAgB,CAC1B,CAAC,SAAS,IAAI,EACd,OAAO,SAAS,IAAI,EACpB,IAAI,GAAG,OAAO,IACZ,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,OAAO,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC;AAErE,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,cAAc,EACxB,IAAI,EAAE,cAAc,GACnB,OAAO,CAKT"}
|
package/dist/utils.js
CHANGED
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,YAAY,CAC1B,QAAwB,EACxB,IAAoB;IAEpB,OAAO,CACL,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;QAC/B,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAC5D,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Based on {@link https://github.com/juliencrn/usehooks-ts}
|
|
3
|
-
*
|
|
4
|
-
* @license MIT
|
|
5
|
-
* @copyright 2020 Julien CARON
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
1
|
import { useEffect, useMemo, useRef, type RefObject } from 'react';
|
|
9
2
|
|
|
10
3
|
/**
|
|
@@ -13,27 +6,36 @@ import { useEffect, useMemo, useRef, type RefObject } from 'react';
|
|
|
13
6
|
* @see
|
|
14
7
|
* {@linkcode useEventListener},
|
|
15
8
|
* {@linkcode UseEventListenerWithImplicitWindowTarget},
|
|
16
|
-
* {@linkcode
|
|
9
|
+
* {@linkcode UseEventListenerWithExplicitGlobalTarget},
|
|
17
10
|
* {@linkcode UseEventListenerWithAnyExplicitTarget}
|
|
18
11
|
*/
|
|
19
12
|
export type UseEventListener = UseEventListenerWithImplicitWindowTarget &
|
|
20
|
-
|
|
21
|
-
UseEventListenerWithExplicitTarget<Document, DocumentEventMap> &
|
|
22
|
-
UseEventListenerWithExplicitTarget<HTMLElement, HTMLElementEventMap> &
|
|
23
|
-
UseEventListenerWithExplicitTarget<SVGElement, SVGElementEventMap> &
|
|
24
|
-
UseEventListenerWithExplicitTarget<MathMLElement, MathMLElementEventMap> &
|
|
13
|
+
UseEventListenerWithExplicitGlobalTarget &
|
|
25
14
|
UseEventListenerWithAnyExplicitTarget;
|
|
26
15
|
|
|
27
16
|
/**
|
|
28
17
|
* @see
|
|
29
18
|
* {@linkcode useEventListener},
|
|
30
|
-
* {@linkcode UseEventListenerWithImplicitWindowTargetArgs}
|
|
19
|
+
* {@linkcode UseEventListenerWithImplicitWindowTargetArgs}
|
|
20
|
+
*/
|
|
31
21
|
export type UseEventListenerWithImplicitWindowTarget = <
|
|
32
22
|
K extends keyof WindowEventMap,
|
|
33
23
|
>(
|
|
34
24
|
...args: UseEventListenerWithImplicitWindowTargetArgs<K>
|
|
35
25
|
) => void;
|
|
36
26
|
|
|
27
|
+
/**
|
|
28
|
+
* @see
|
|
29
|
+
* {@linkcode useEventListener},
|
|
30
|
+
* {@linkcode UseEventListenerWithExplicitTarget}
|
|
31
|
+
*/
|
|
32
|
+
export type UseEventListenerWithExplicitGlobalTarget =
|
|
33
|
+
UseEventListenerWithExplicitTarget<Window, WindowEventMap> &
|
|
34
|
+
UseEventListenerWithExplicitTarget<Document, DocumentEventMap> &
|
|
35
|
+
UseEventListenerWithExplicitTarget<HTMLElement, HTMLElementEventMap> &
|
|
36
|
+
UseEventListenerWithExplicitTarget<SVGElement, SVGElementEventMap> &
|
|
37
|
+
UseEventListenerWithExplicitTarget<MathMLElement, MathMLElementEventMap>;
|
|
38
|
+
|
|
37
39
|
/**
|
|
38
40
|
* @see
|
|
39
41
|
* {@linkcode useEventListener},
|
|
@@ -149,7 +151,9 @@ export const useEventListener: UseEventListener = function useEventListener(
|
|
|
149
151
|
target && !('addEventListener' in target) ? target.current : target;
|
|
150
152
|
|
|
151
153
|
const handlerRef = useRef(handler);
|
|
152
|
-
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
handlerRef.current = handler;
|
|
156
|
+
}, [handler]);
|
|
153
157
|
|
|
154
158
|
const {
|
|
155
159
|
capture = false,
|
|
@@ -11,54 +11,10 @@ import type { useReducerWithDeps } from './useReducerWithDeps.js';
|
|
|
11
11
|
* This hook is designed in the most general way possible in order to cover all
|
|
12
12
|
* imaginable use cases.
|
|
13
13
|
*
|
|
14
|
-
* @
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* Here is an example of a scenario where that can make sense:
|
|
19
|
-
*
|
|
20
|
-
* ```tsx
|
|
21
|
-
* type SensorData = { timestamp: number; value: number };
|
|
22
|
-
* const sensorDataRef = useRef<SensorData[]>([]);
|
|
23
|
-
* const mostRecentSensorDataTimestampRef = useRef<number>(0);
|
|
24
|
-
*
|
|
25
|
-
* const [forceUpdate, updateCount] = useForceUpdate();
|
|
26
|
-
* // Limiting the frequency of forced re-renders with some throttle function:
|
|
27
|
-
* const throttledForceUpdateRef = useRef(throttle(forceUpdate));
|
|
28
|
-
*
|
|
29
|
-
* useEffect(() => {
|
|
30
|
-
* return sensorDataObservable.subscribe((data: SensorData) => {
|
|
31
|
-
* // Imagine new sensor data arrives every 1 millisecond. If we were following
|
|
32
|
-
* // React's immutability rules by creating a new array every time, the data
|
|
33
|
-
* // that's already there would have to be copied many times before the new
|
|
34
|
-
* // data would even get a chance to be reflected in the UI for the first time
|
|
35
|
-
* // because it typically takes much longer than 1 millisecond for a new frame
|
|
36
|
-
* // to be displayed. To prevent the waste of computational resources, we just
|
|
37
|
-
* // mutate the existing array every time instead:
|
|
38
|
-
* sensorDataRef.current.push(data);
|
|
39
|
-
* if (data.timestamp > mostRecentSensorDataTimestampRef.current) {
|
|
40
|
-
* mostRecentSensorDataTimestampRef.current = data.timestamp;
|
|
41
|
-
* }
|
|
42
|
-
* throttledForceUpdateRef.current();
|
|
43
|
-
* });
|
|
44
|
-
* }, []);
|
|
45
|
-
*
|
|
46
|
-
* const [timeWindow, setTimeWindow] = useState(1000);
|
|
47
|
-
* const selectedSensorData = useMemo(
|
|
48
|
-
* () => {
|
|
49
|
-
* // Keep this line if you don't want to disable the
|
|
50
|
-
* // react-hooks/exhaustive-deps ESLint rule:
|
|
51
|
-
* updateCount;
|
|
52
|
-
* const threshold = mostRecentSensorDataTimestampRef.current - timeWindow;
|
|
53
|
-
* return sensorDataRef.current.filter(
|
|
54
|
-
* ({ timestamp }) => timestamp >= threshold,
|
|
55
|
-
* );
|
|
56
|
-
* },
|
|
57
|
-
* // sensorDataRef.current always references the same array, so listing it as a
|
|
58
|
-
* // dependency is pointless. Instead, updateCount should be used:
|
|
59
|
-
* [updateCount, timeWindow],
|
|
60
|
-
* );
|
|
61
|
-
* ```
|
|
14
|
+
* @deprecated
|
|
15
|
+
* This hook encourages patterns that are unsafe in Concurrent React.
|
|
16
|
+
* For details and ideas on how to get rid of it, please check the discussion at
|
|
17
|
+
* https://www.reddit.com/r/react/comments/1nqcsri/comment/ng76cv5/.
|
|
62
18
|
*
|
|
63
19
|
* @param callback An optional callback function to call during renders that
|
|
64
20
|
* were triggered with `forceUpdate()`
|
|
@@ -18,6 +18,13 @@ export type ActionDispatch<ActionArg extends AnyActionArg> = (
|
|
|
18
18
|
* `useReducer` hook with an additional dependency array `deps` that resets the
|
|
19
19
|
* state to `initialState` when dependencies change
|
|
20
20
|
*
|
|
21
|
+
* This hook is the reducer pattern counterpart of {@linkcode useStateWithDeps}.
|
|
22
|
+
*
|
|
23
|
+
* Due to React's limitations, a change in dependencies always causes two
|
|
24
|
+
* renders when using this hook. The result of the first render is thrown away
|
|
25
|
+
* as described in
|
|
26
|
+
* [useState > Storing information from previous renders](https://react.dev/reference/react/useState#storing-information-from-previous-renders).
|
|
27
|
+
*
|
|
21
28
|
* For motivation and examples, see
|
|
22
29
|
* https://github.com/facebook/react/issues/33041.
|
|
23
30
|
*
|
|
@@ -60,9 +67,9 @@ export function useReducerWithDeps<S, A extends AnyActionArg>(
|
|
|
60
67
|
// Only the initially provided reducer is used
|
|
61
68
|
const reducerRef = useRef(reducer);
|
|
62
69
|
|
|
63
|
-
|
|
70
|
+
function dispatch(...args: A): void {
|
|
64
71
|
setState((previousState) => reducerRef.current(previousState, ...args));
|
|
65
|
-
}
|
|
72
|
+
}
|
|
66
73
|
|
|
67
|
-
return [state, dispatch];
|
|
74
|
+
return [state, useRef(dispatch).current];
|
|
68
75
|
}
|
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Based on {@link https://github.com/peterjuras/use-state-with-deps}
|
|
3
|
-
*
|
|
4
|
-
* @license MIT
|
|
5
|
-
* @copyright 2020 Peter Juras
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
1
|
import {
|
|
9
|
-
|
|
2
|
+
useState,
|
|
10
3
|
type DependencyList,
|
|
11
4
|
type Dispatch,
|
|
12
5
|
type SetStateAction,
|
|
13
6
|
} from 'react';
|
|
14
|
-
import { depsAreEqual
|
|
15
|
-
import { useForceUpdate } from './useForceUpdate.js';
|
|
7
|
+
import { depsAreEqual } from '../utils.js';
|
|
16
8
|
|
|
17
9
|
/**
|
|
18
10
|
* `useState` hook with an additional dependency array `deps` that resets the
|
|
19
11
|
* state to `initialState` when dependencies change
|
|
20
12
|
*
|
|
13
|
+
* Due to React's limitations, a change in dependencies always causes two
|
|
14
|
+
* renders when using this hook. The result of the first render is thrown away
|
|
15
|
+
* as described in
|
|
16
|
+
* [useState > Storing information from previous renders](https://react.dev/reference/react/useState#storing-information-from-previous-renders).
|
|
17
|
+
*
|
|
21
18
|
* For motivation and more examples, see
|
|
22
19
|
* https://github.com/facebook/react/issues/33041.
|
|
23
20
|
*
|
|
@@ -36,7 +33,7 @@ import { useForceUpdate } from './useForceUpdate.js';
|
|
|
36
33
|
* evening: ['board games', 'dinner'],
|
|
37
34
|
* };
|
|
38
35
|
*
|
|
39
|
-
*
|
|
36
|
+
* function Example() {
|
|
40
37
|
* const [timeOfDay, setTimeOfDay] = useState<TimeOfDay>('morning');
|
|
41
38
|
*
|
|
42
39
|
* const activityOptions = activityOptionsByTimeOfDay[timeOfDay];
|
|
@@ -66,45 +63,14 @@ export function useStateWithDeps<S>(
|
|
|
66
63
|
initialState: S | ((previousState?: S) => S),
|
|
67
64
|
deps: DependencyList,
|
|
68
65
|
): [S, Dispatch<SetStateAction<S>>] {
|
|
69
|
-
|
|
70
|
-
// however this would trigger re-renders whenever the state is reset due to a
|
|
71
|
-
// change in dependencies. In order to avoid these re-renders, the state is
|
|
72
|
-
// stored in a ref, and updates are triggered with forceUpdate when necessary.
|
|
73
|
-
const state = useRef(undefined as S);
|
|
66
|
+
const [state, setState] = useState(initialState);
|
|
74
67
|
|
|
75
|
-
const prevDeps =
|
|
76
|
-
const isMounted = useRef(false);
|
|
68
|
+
const [prevDeps, setPrevDeps] = useState(deps);
|
|
77
69
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
let nextState: S;
|
|
82
|
-
if (isFunction(initialState)) {
|
|
83
|
-
nextState = initialState(state.current);
|
|
84
|
-
} else {
|
|
85
|
-
nextState = initialState;
|
|
86
|
-
}
|
|
87
|
-
state.current = nextState;
|
|
88
|
-
prevDeps.current = deps;
|
|
89
|
-
isMounted.current = true;
|
|
70
|
+
if (!depsAreEqual(deps, prevDeps)) {
|
|
71
|
+
setPrevDeps(deps);
|
|
72
|
+
setState(initialState);
|
|
90
73
|
}
|
|
91
74
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const updateState = useRef(function updateState(
|
|
95
|
-
newState: S | ((previousState: S) => S),
|
|
96
|
-
): void {
|
|
97
|
-
let nextState: S;
|
|
98
|
-
if (isFunction(newState)) {
|
|
99
|
-
nextState = newState(state.current);
|
|
100
|
-
} else {
|
|
101
|
-
nextState = newState;
|
|
102
|
-
}
|
|
103
|
-
if (!Object.is(state.current, nextState)) {
|
|
104
|
-
state.current = nextState;
|
|
105
|
-
forceUpdate();
|
|
106
|
-
}
|
|
107
|
-
}).current;
|
|
108
|
-
|
|
109
|
-
return [state.current, updateState];
|
|
75
|
+
return [state, setState];
|
|
110
76
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import type { DependencyList } from 'react';
|
|
2
2
|
|
|
3
|
-
export type Callable = (...args: never) => unknown;
|
|
4
|
-
|
|
5
3
|
export type ArgumentFallback<
|
|
6
4
|
T extends Base,
|
|
7
5
|
Default extends Base,
|
|
8
6
|
Base = unknown,
|
|
9
7
|
> = [T] extends [never] ? Default : [Base] extends [T] ? Default : T;
|
|
10
8
|
|
|
11
|
-
export function noop() {}
|
|
12
|
-
|
|
13
|
-
export function isFunction(input: unknown): input is Callable {
|
|
14
|
-
return typeof input === 'function';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
9
|
export function depsAreEqual(
|
|
18
10
|
prevDeps: DependencyList,
|
|
19
11
|
deps: DependencyList,
|