@aweebit/react-essentials 0.4.0 → 0.5.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.
Files changed (36) hide show
  1. package/LICENSE +2 -0
  2. package/dist/hooks/useEventListener.d.ts +2 -21
  3. package/dist/hooks/useEventListener.d.ts.map +1 -1
  4. package/dist/hooks/useEventListener.js +2 -20
  5. package/dist/hooks/useEventListener.js.map +1 -0
  6. package/dist/hooks/useForceUpdate.d.ts +26 -4
  7. package/dist/hooks/useForceUpdate.d.ts.map +1 -1
  8. package/dist/hooks/useForceUpdate.js +37 -4
  9. package/dist/hooks/useForceUpdate.js.map +1 -0
  10. package/dist/hooks/useReducerWithDeps.d.ts +36 -0
  11. package/dist/hooks/useReducerWithDeps.d.ts.map +1 -0
  12. package/dist/hooks/useReducerWithDeps.js +46 -0
  13. package/dist/hooks/useReducerWithDeps.js.map +1 -0
  14. package/dist/hooks/useStateWithDeps.d.ts +23 -0
  15. package/dist/hooks/useStateWithDeps.d.ts.map +1 -0
  16. package/dist/hooks/useStateWithDeps.js +64 -0
  17. package/dist/hooks/useStateWithDeps.js.map +1 -0
  18. package/dist/index.d.ts +2 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +3 -1
  21. package/dist/index.js.map +1 -0
  22. package/dist/utils/index.d.ts +0 -0
  23. package/dist/utils/index.d.ts.map +0 -0
  24. package/dist/utils/index.js +1 -0
  25. package/dist/utils/index.js.map +1 -0
  26. package/lib/hooks/useEventListener.ts +2 -21
  27. package/lib/hooks/useForceUpdate.ts +38 -7
  28. package/lib/hooks/useReducerWithDeps.ts +59 -0
  29. package/lib/hooks/useStateWithDeps.ts +79 -0
  30. package/lib/index.ts +2 -1
  31. package/lib/utils/index.ts +0 -0
  32. package/package.json +5 -3
  33. package/dist/hooks/useDerivedState.d.ts +0 -42
  34. package/dist/hooks/useDerivedState.d.ts.map +0 -1
  35. package/dist/hooks/useDerivedState.js +0 -92
  36. package/lib/hooks/useDerivedState.ts +0 -108
package/LICENSE CHANGED
@@ -1,6 +1,8 @@
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
4
6
 
5
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
8
  of this software and associated documentation files (the "Software"), to deal
@@ -2,30 +2,11 @@
2
2
  * @file Based on {@link https://github.com/juliencrn/usehooks-ts}
3
3
  *
4
4
  * @license MIT
5
- *
6
- * Copyright (c) 2020 Julien CARON
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in all
16
- * copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- * SOFTWARE.
5
+ * @copyright 2020 Julien CARON
25
6
  */
26
7
  /**
27
8
  * Adds `handler` as a listener for the event `eventName` of `element`
28
- * (or `window` by default) with the provided `options` applied.
9
+ * (or `window` by default) with the provided `options` applied
29
10
  *
30
11
  * It is the user's responsibility to make sure `element` and `options` values
31
12
  * are correctly memoized!
@@ -1 +1 @@
1
- {"version":3,"file":"useEventListener.d.ts","sourceRoot":"","sources":["../../lib/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH;;;;;;GAMG;AAGH,iBAAS,gBAAgB,CACvB,CAAC,SAAS,MAAM,kBAAkB,EAClC,CAAC,SAAS,UAAU,EAEpB,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC/C,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;AAGR,iBAAS,gBAAgB,CACvB,CAAC,SAAS,MAAM,mBAAmB,EACnC,CAAC,SAAS,WAAW,EAErB,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAChD,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;AAGR,iBAAS,gBAAgB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EACxD,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC7C,OAAO,EAAE,QAAQ,EACjB,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;AAGR,iBAAS,gBAAgB,CAAC,CAAC,SAAS,MAAM,cAAc,EACtD,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,EAC3C,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;AAiCR,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"useEventListener.d.ts","sourceRoot":"","sources":["../../lib/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;GAMG;AAGH,iBAAS,gBAAgB,CACvB,CAAC,SAAS,MAAM,kBAAkB,EAClC,CAAC,SAAS,UAAU,EAEpB,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC/C,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;AAGR,iBAAS,gBAAgB,CACvB,CAAC,SAAS,MAAM,mBAAmB,EACnC,CAAC,SAAS,WAAW,EAErB,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAChD,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;AAGR,iBAAS,gBAAgB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EACxD,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC7C,OAAO,EAAE,QAAQ,EACjB,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;AAGR,iBAAS,gBAAgB,CAAC,CAAC,SAAS,MAAM,cAAc,EACtD,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,EAC3C,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,OAAO,GAAG,uBAAuB,GAC1C,IAAI,CAAC;AAiCR,eAAe,gBAAgB,CAAC"}
@@ -2,26 +2,7 @@
2
2
  * @file Based on {@link https://github.com/juliencrn/usehooks-ts}
3
3
  *
4
4
  * @license MIT
5
- *
6
- * Copyright (c) 2020 Julien CARON
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in all
16
- * copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- * SOFTWARE.
5
+ * @copyright 2020 Julien CARON
25
6
  */
26
7
  import { useEffect, useLayoutEffect, useRef } from 'react';
27
8
  function useEventListener(eventName, handler, element, options) {
@@ -45,3 +26,4 @@ function useEventListener(eventName, handler, element, options) {
45
26
  }, [eventName, element, options]);
46
27
  }
47
28
  export default useEventListener;
29
+ //# sourceMappingURL=useEventListener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEventListener.js","sourceRoot":"","sources":["../../lib/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAgD3D,SAAS,gBAAgB,CACvB,SAAiB,EACjB,OAA+B,EAC/B,OAAqB,EACrB,OAA2C;IAE3C,mCAAmC;IACnC,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAErC,eAAe,CAAC,GAAG,EAAE;QACnB,YAAY,CAAC,OAAO,GAAG,OAAO,CAAC;IACjC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,SAAS,CAAC,GAAG,EAAE;QACb,8BAA8B;QAC9B,MAAM,aAAa,GAAG,OAAO,IAAI,MAAM,CAAC;QAExC,kEAAkE;QAClE,MAAM,QAAQ,GAAmB,CAAC,KAAK,EAAE,EAAE;YACzC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC,CAAC;QAEF,aAAa,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE7D,mCAAmC;QACnC,OAAO,GAAG,EAAE;YACV,aAAa,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClE,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,eAAe,gBAAgB,CAAC"}
@@ -1,5 +1,27 @@
1
- export default function useForceUpdate(): [
2
- () => void,
3
- Record<PropertyKey, never>
4
- ];
1
+ /**
2
+ * Enables you to imperatively trigger re-rendering of components
3
+ *
4
+ * This hook is designed in the most general way possible in order to cover all
5
+ * imaginable use cases.
6
+ *
7
+ * @param callback An optional callback function to call during renders that
8
+ * were triggered with `forceUpdate()`
9
+ *
10
+ * Can be used for conditionally calling state setters when state needs to be
11
+ * reset. That is legal and better than using effects (see
12
+ * {@link https://react.dev/learn/-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes You Might Not Need an Effect > Adjusting some state when a prop changes}),
13
+ * but can often be avoided by using
14
+ * [`useStateWithDeps`]({@link ./useStateWithDeps.ts}) or
15
+ * [`useReducerWithDeps`]({@link ./useReducerWithDeps.ts}).
16
+ *
17
+ * Important: the callback function is called once per render, not once per
18
+ * `forceUpdate` call! If React batches `forceUpdate` calls, then it will only
19
+ * be called once.
20
+ *
21
+ * @returns An array with the following two elements:
22
+ *
23
+ * 1. A `forceUpdate` function that triggers a re-render
24
+ * 2. The number of times `forceUpdate` has been called so far
25
+ */
26
+ export default function useForceUpdate(callback?: () => void): [() => void, bigint];
5
27
  //# sourceMappingURL=useForceUpdate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useForceUpdate.d.ts","sourceRoot":"","sources":["../../lib/hooks/useForceUpdate.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,cAAc,IAAI;IACxC,MAAM,IAAI;IACV,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC;CAC3B,CAGA"}
1
+ {"version":3,"file":"useForceUpdate.d.ts","sourceRoot":"","sources":["../../lib/hooks/useForceUpdate.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CACpC,QAAQ,CAAC,EAAE,MAAM,IAAI,GACpB,CAAC,MAAM,IAAI,EAAE,MAAM,CAAC,CAUtB"}
@@ -1,5 +1,38 @@
1
- import { useReducer } from 'react';
2
- export default function useForceUpdate() {
3
- const [value, forceUpdate] = useReducer(() => ({}), {});
4
- return [forceUpdate, value];
1
+ import { useReducer, useRef } from 'react';
2
+ /**
3
+ * Enables you to imperatively trigger re-rendering of components
4
+ *
5
+ * This hook is designed in the most general way possible in order to cover all
6
+ * imaginable use cases.
7
+ *
8
+ * @param callback An optional callback function to call during renders that
9
+ * were triggered with `forceUpdate()`
10
+ *
11
+ * Can be used for conditionally calling state setters when state needs to be
12
+ * reset. That is legal and better than using effects (see
13
+ * {@link https://react.dev/learn/-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes You Might Not Need an Effect > Adjusting some state when a prop changes}),
14
+ * but can often be avoided by using
15
+ * [`useStateWithDeps`]({@link ./useStateWithDeps.ts}) or
16
+ * [`useReducerWithDeps`]({@link ./useReducerWithDeps.ts}).
17
+ *
18
+ * Important: the callback function is called once per render, not once per
19
+ * `forceUpdate` call! If React batches `forceUpdate` calls, then it will only
20
+ * be called once.
21
+ *
22
+ * @returns An array with the following two elements:
23
+ *
24
+ * 1. A `forceUpdate` function that triggers a re-render
25
+ * 2. The number of times `forceUpdate` has been called so far
26
+ */
27
+ export default function useForceUpdate(callback) {
28
+ // It is very unlikely that the number of updates will exceed
29
+ // Number.MAX_SAFE_INTEGER, but not impossible. That is why we use bigints.
30
+ const [counter, forceUpdate] = useReducer((prev) => prev + 1n, 0n);
31
+ const counterRef = useRef(counter);
32
+ if (counter !== counterRef.current) {
33
+ counterRef.current = counter;
34
+ callback?.();
35
+ }
36
+ return [forceUpdate, counter];
5
37
  }
38
+ //# sourceMappingURL=useForceUpdate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useForceUpdate.js","sourceRoot":"","sources":["../../lib/hooks/useForceUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CACpC,QAAqB;IAErB,6DAA6D;IAC7D,2EAA2E;IAC3E,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IACnE,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,CAAC;QACnC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;QAC7B,QAAQ,EAAE,EAAE,CAAC;IACf,CAAC;IACD,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { type ActionDispatch, type AnyActionArg, type DependencyList } from 'react';
2
+ /**
3
+ * `useReducer` hook with an additional dependency array that resets the state
4
+ * to the `initialState` param when the dependencies passed in the `deps` array
5
+ * change
6
+ *
7
+ * ### On linter support
8
+ *
9
+ * The `react-hooks/exhaustive-deps` ESLint rule doesn't support hooks where
10
+ * the dependency array parameter is at any other position than the second.
11
+ * However, as we would like to keep the hook as compatible with `useReducer` as
12
+ * possible, we don't want to artificially change the parameter's position.
13
+ * Therefore, there will be no warnings about missing dependencies.
14
+ * Because of that, addition caution is advised!
15
+ * Be sure to check no dependencies are missing from the `deps` array.
16
+ *
17
+ * Related issue: {@link https://github.com/facebook/react/issues/25443}.
18
+ *
19
+ * Unlike `eslint-plugin-react-hooks` maintained by React's team, the unofficial
20
+ * `useExhaustiveDependencies` rule provided for Biome by Biome's team
21
+ * does actually have support for dependency arrays at other positions, see
22
+ * {@link https://biomejs.dev/linter/rules/use-exhaustive-dependencies/#validating-dependencies}.
23
+ *
24
+ * @param reducer The reducer function that specifies how the state gets updated
25
+ *
26
+ * @param initialState The state that will be set when the component mounts or
27
+ * the dependencies change
28
+ *
29
+ * It can also be a function which returns a state value. If the state is reset
30
+ * due to a change of dependencies, this function will be passed the previous
31
+ * state as its argument (will be `undefined` in the first call upon mount).
32
+ *
33
+ * @param deps Dependencies that reset the state to `initialState`
34
+ */
35
+ export default function useReducerWithDeps<S, A extends AnyActionArg>(reducer: (prevState: S, ...args: A) => S, initialState: S | ((previousState?: S) => S), deps: DependencyList): [S, ActionDispatch<A>];
36
+ //# sourceMappingURL=useReducerWithDeps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useReducerWithDeps.d.ts","sourceRoot":"","sources":["../../lib/hooks/useReducerWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,cAAc,EAGpB,MAAM,OAAO,CAAC;AAGf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,CAAC,EAAE,CAAC,SAAS,YAAY,EAClE,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"}
@@ -0,0 +1,46 @@
1
+ import { useCallback, useRef, } from 'react';
2
+ import useStateWithDeps from './useStateWithDeps';
3
+ /**
4
+ * `useReducer` hook with an additional dependency array that resets the state
5
+ * to the `initialState` param when the dependencies passed in the `deps` array
6
+ * change
7
+ *
8
+ * ### On linter support
9
+ *
10
+ * The `react-hooks/exhaustive-deps` ESLint rule doesn't support hooks where
11
+ * the dependency array parameter is at any other position than the second.
12
+ * However, as we would like to keep the hook as compatible with `useReducer` as
13
+ * possible, we don't want to artificially change the parameter's position.
14
+ * Therefore, there will be no warnings about missing dependencies.
15
+ * Because of that, addition caution is advised!
16
+ * Be sure to check no dependencies are missing from the `deps` array.
17
+ *
18
+ * Related issue: {@link https://github.com/facebook/react/issues/25443}.
19
+ *
20
+ * Unlike `eslint-plugin-react-hooks` maintained by React's team, the unofficial
21
+ * `useExhaustiveDependencies` rule provided for Biome by Biome's team
22
+ * does actually have support for dependency arrays at other positions, see
23
+ * {@link https://biomejs.dev/linter/rules/use-exhaustive-dependencies/#validating-dependencies}.
24
+ *
25
+ * @param reducer The reducer function that specifies how the state gets updated
26
+ *
27
+ * @param initialState The state that will be set when the component mounts or
28
+ * the dependencies change
29
+ *
30
+ * It can also be a function which returns a state value. If the state is reset
31
+ * due to a change of dependencies, this function will be passed the previous
32
+ * state as its argument (will be `undefined` in the first call upon mount).
33
+ *
34
+ * @param deps Dependencies that reset the state to `initialState`
35
+ */
36
+ export default function useReducerWithDeps(reducer, initialState, deps) {
37
+ // eslint-disable-next-line react-hooks/exhaustive-deps
38
+ const [state, setState] = useStateWithDeps(initialState, deps);
39
+ // Only the initially provided reducer is used
40
+ const reducerRef = useRef(reducer);
41
+ const dispatch = useCallback(function dispatch(...args) {
42
+ setState((previousState) => reducerRef.current(previousState, ...args));
43
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
44
+ return [state, dispatch];
45
+ }
46
+ //# sourceMappingURL=useReducerWithDeps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useReducerWithDeps.js","sourceRoot":"","sources":["../../lib/hooks/useReducerWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,WAAW,EACX,MAAM,GACP,MAAM,OAAO,CAAC;AACf,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CACxC,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,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,QAAQ,CAAC,GAAG,IAAO;QACvD,QAAQ,CAAC,CAAC,aAAa,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kDAAkD;IAE1D,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,23 @@
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
+ import { type DependencyList, type Dispatch, type SetStateAction } from 'react';
8
+ /**
9
+ * `useState` hook with an additional dependency array that resets the state
10
+ * to the `initialState` param when the dependencies passed in the `deps` array
11
+ * change
12
+ *
13
+ * @param initialState The state that will be set when the component mounts or
14
+ * the dependencies change
15
+ *
16
+ * It can also be a function which returns a state value. If the state is reset
17
+ * due to a change of dependencies, this function will be passed the previous
18
+ * state as its argument (will be `undefined` in the first call upon mount).
19
+ *
20
+ * @param deps Dependencies that reset the state to `initialState`
21
+ */
22
+ export default function useStateWithDeps<S>(initialState: S | ((previousState?: S) => S), deps: DependencyList): [S, Dispatch<SetStateAction<S>>];
23
+ //# sourceMappingURL=useStateWithDeps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStateWithDeps.d.ts","sourceRoot":"","sources":["../../lib/hooks/useStateWithDeps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAIf;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,CAAC,EACxC,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,CA4ClC"}
@@ -0,0 +1,64 @@
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
+ import { useCallback, useRef, } from 'react';
8
+ import { depsAreEqual, isFunction } from '../utils';
9
+ import useForceUpdate from './useForceUpdate';
10
+ /**
11
+ * `useState` hook with an additional dependency array that resets the state
12
+ * to the `initialState` param when the dependencies passed in the `deps` array
13
+ * change
14
+ *
15
+ * @param initialState The state that will be set when the component mounts or
16
+ * the dependencies change
17
+ *
18
+ * It can also be a function which returns a state value. If the state is reset
19
+ * due to a change of dependencies, this function will be passed the previous
20
+ * state as its argument (will be `undefined` in the first call upon mount).
21
+ *
22
+ * @param deps Dependencies that reset the state to `initialState`
23
+ */
24
+ export default function useStateWithDeps(initialState, deps) {
25
+ // It would be possible to use useState instead of
26
+ // useRef to store the state, however this would
27
+ // trigger re-renders whenever the state is reset due
28
+ // to a change in dependencies. In order to avoid these
29
+ // re-renders, the state is stored in a ref and an
30
+ // update is triggered via forceUpdate below when necessary
31
+ const state = useRef(undefined);
32
+ const prevDeps = useRef(deps);
33
+ const isMounted = useRef(false);
34
+ // If first render, or if dependencies have changed since last time
35
+ if (!isMounted.current || !depsAreEqual(prevDeps.current, deps)) {
36
+ // Update state and deps
37
+ let nextState;
38
+ if (isFunction(initialState)) {
39
+ nextState = initialState(state.current);
40
+ }
41
+ else {
42
+ nextState = initialState;
43
+ }
44
+ state.current = nextState;
45
+ prevDeps.current = deps;
46
+ isMounted.current = true;
47
+ }
48
+ const [forceUpdate] = useForceUpdate();
49
+ const updateState = useCallback(function updateState(newState) {
50
+ let nextState;
51
+ if (isFunction(newState)) {
52
+ nextState = newState(state.current);
53
+ }
54
+ else {
55
+ nextState = newState;
56
+ }
57
+ if (!Object.is(state.current, nextState)) {
58
+ state.current = nextState;
59
+ forceUpdate();
60
+ }
61
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
62
+ return [state.current, updateState];
63
+ }
64
+ //# sourceMappingURL=useStateWithDeps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStateWithDeps.js","sourceRoot":"","sources":["../../lib/hooks/useStateWithDeps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,WAAW,EACX,MAAM,GAIP,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAE9C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,YAA4C,EAC5C,IAAoB;IAEpB,kDAAkD;IAClD,gDAAgD;IAChD,qDAAqD;IACrD,uDAAuD;IACvD,kDAAkD;IAClD,2DAA2D;IAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,SAAc,CAAC,CAAC;IAErC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEhC,mEAAmE;IACnE,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QAChE,wBAAwB;QACxB,IAAI,SAAY,CAAC;QACjB,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,YAAY,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;QAC1B,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,GAAG,cAAc,EAAE,CAAC;IAEvC,MAAM,WAAW,GAAG,WAAW,CAAC,SAAS,WAAW,CAClD,QAAuC;QAEvC,IAAI,SAAY,CAAC;QACjB,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,QAAQ,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;YACzC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;YAC1B,WAAW,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kDAAkD;IAE1D,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;AACtC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export { default as useDerivedState } from './hooks/useDerivedState';
2
1
  export { default as useEventListener } from './hooks/useEventListener';
3
2
  export { default as useForceUpdate } from './hooks/useForceUpdate';
3
+ export { default as useReducerWithDeps } from './hooks/useReducerWithDeps';
4
+ export { default as useStateWithDeps } from './hooks/useStateWithDeps';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
- export { default as useDerivedState } from './hooks/useDerivedState';
2
1
  export { default as useEventListener } from './hooks/useEventListener';
3
2
  export { default as useForceUpdate } from './hooks/useForceUpdate';
3
+ export { default as useReducerWithDeps } from './hooks/useReducerWithDeps';
4
+ export { default as useStateWithDeps } from './hooks/useStateWithDeps';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAC"}
File without changes
File without changes
@@ -6,3 +6,4 @@ export function depsAreEqual(prevDeps, deps) {
6
6
  return (prevDeps.length === deps.length &&
7
7
  deps.every((dep, index) => Object.is(dep, prevDeps[index])));
8
8
  }
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/utils/index.ts"],"names":[],"mappings":"AAEA,sEAAsE;AACtE,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC;AACrC,CAAC;AAED,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"}
@@ -2,33 +2,14 @@
2
2
  * @file Based on {@link https://github.com/juliencrn/usehooks-ts}
3
3
  *
4
4
  * @license MIT
5
- *
6
- * Copyright (c) 2020 Julien CARON
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in all
16
- * copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- * SOFTWARE.
5
+ * @copyright 2020 Julien CARON
25
6
  */
26
7
 
27
8
  import { useEffect, useLayoutEffect, useRef } from 'react';
28
9
 
29
10
  /**
30
11
  * Adds `handler` as a listener for the event `eventName` of `element`
31
- * (or `window` by default) with the provided `options` applied.
12
+ * (or `window` by default) with the provided `options` applied
32
13
  *
33
14
  * It is the user's responsibility to make sure `element` and `options` values
34
15
  * are correctly memoized!
@@ -1,9 +1,40 @@
1
- import { useReducer } from 'react';
1
+ import { useReducer, useRef } from 'react';
2
2
 
3
- export default function useForceUpdate(): [
4
- () => void,
5
- Record<PropertyKey, never>,
6
- ] {
7
- const [value, forceUpdate] = useReducer(() => ({}), {});
8
- return [forceUpdate, value];
3
+ /**
4
+ * Enables you to imperatively trigger re-rendering of components
5
+ *
6
+ * This hook is designed in the most general way possible in order to cover all
7
+ * imaginable use cases.
8
+ *
9
+ * @param callback An optional callback function to call during renders that
10
+ * were triggered with `forceUpdate()`
11
+ *
12
+ * Can be used for conditionally calling state setters when state needs to be
13
+ * reset. That is legal and better than using effects (see
14
+ * {@link https://react.dev/learn/-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes You Might Not Need an Effect > Adjusting some state when a prop changes}),
15
+ * but can often be avoided by using
16
+ * [`useStateWithDeps`]({@link ./useStateWithDeps.ts}) or
17
+ * [`useReducerWithDeps`]({@link ./useReducerWithDeps.ts}).
18
+ *
19
+ * Important: the callback function is called once per render, not once per
20
+ * `forceUpdate` call! If React batches `forceUpdate` calls, then it will only
21
+ * be called once.
22
+ *
23
+ * @returns An array with the following two elements:
24
+ *
25
+ * 1. A `forceUpdate` function that triggers a re-render
26
+ * 2. The number of times `forceUpdate` has been called so far
27
+ */
28
+ export default function useForceUpdate(
29
+ callback?: () => void,
30
+ ): [() => void, bigint] {
31
+ // It is very unlikely that the number of updates will exceed
32
+ // Number.MAX_SAFE_INTEGER, but not impossible. That is why we use bigints.
33
+ const [counter, forceUpdate] = useReducer((prev) => prev + 1n, 0n);
34
+ const counterRef = useRef(counter);
35
+ if (counter !== counterRef.current) {
36
+ counterRef.current = counter;
37
+ callback?.();
38
+ }
39
+ return [forceUpdate, counter];
9
40
  }
@@ -0,0 +1,59 @@
1
+ import {
2
+ type ActionDispatch,
3
+ type AnyActionArg,
4
+ type DependencyList,
5
+ useCallback,
6
+ useRef,
7
+ } from 'react';
8
+ import useStateWithDeps from './useStateWithDeps';
9
+
10
+ /**
11
+ * `useReducer` hook with an additional dependency array that resets the state
12
+ * to the `initialState` param when the dependencies passed in the `deps` array
13
+ * change
14
+ *
15
+ * ### On linter support
16
+ *
17
+ * The `react-hooks/exhaustive-deps` ESLint rule doesn't support hooks where
18
+ * the dependency array parameter is at any other position than the second.
19
+ * However, as we would like to keep the hook as compatible with `useReducer` as
20
+ * possible, we don't want to artificially change the parameter's position.
21
+ * Therefore, there will be no warnings about missing dependencies.
22
+ * Because of that, addition caution is advised!
23
+ * Be sure to check no dependencies are missing from the `deps` array.
24
+ *
25
+ * Related issue: {@link https://github.com/facebook/react/issues/25443}.
26
+ *
27
+ * Unlike `eslint-plugin-react-hooks` maintained by React's team, the unofficial
28
+ * `useExhaustiveDependencies` rule provided for Biome by Biome's team
29
+ * does actually have support for dependency arrays at other positions, see
30
+ * {@link https://biomejs.dev/linter/rules/use-exhaustive-dependencies/#validating-dependencies}.
31
+ *
32
+ * @param reducer The reducer function that specifies how the state gets updated
33
+ *
34
+ * @param initialState The state that will be set when the component mounts or
35
+ * the dependencies change
36
+ *
37
+ * It can also be a function which returns a state value. If the state is reset
38
+ * due to a change of dependencies, this function will be passed the previous
39
+ * state as its argument (will be `undefined` in the first call upon mount).
40
+ *
41
+ * @param deps Dependencies that reset the state to `initialState`
42
+ */
43
+ export default function useReducerWithDeps<S, A extends AnyActionArg>(
44
+ reducer: (prevState: S, ...args: A) => S,
45
+ initialState: S | ((previousState?: S) => S),
46
+ deps: DependencyList,
47
+ ): [S, ActionDispatch<A>] {
48
+ // eslint-disable-next-line react-hooks/exhaustive-deps
49
+ const [state, setState] = useStateWithDeps(initialState, deps);
50
+
51
+ // Only the initially provided reducer is used
52
+ const reducerRef = useRef(reducer);
53
+
54
+ const dispatch = useCallback(function dispatch(...args: A): void {
55
+ setState((previousState) => reducerRef.current(previousState, ...args));
56
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
57
+
58
+ return [state, dispatch];
59
+ }
@@ -0,0 +1,79 @@
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
+ import {
9
+ useCallback,
10
+ useRef,
11
+ type DependencyList,
12
+ type Dispatch,
13
+ type SetStateAction,
14
+ } from 'react';
15
+ import { depsAreEqual, isFunction } from '../utils';
16
+ import useForceUpdate from './useForceUpdate';
17
+
18
+ /**
19
+ * `useState` hook with an additional dependency array that resets the state
20
+ * to the `initialState` param when the dependencies passed in the `deps` array
21
+ * change
22
+ *
23
+ * @param initialState The state that will be set when the component mounts or
24
+ * the dependencies change
25
+ *
26
+ * It can also be a function which returns a state value. If the state is reset
27
+ * due to a change of dependencies, this function will be passed the previous
28
+ * state as its argument (will be `undefined` in the first call upon mount).
29
+ *
30
+ * @param deps Dependencies that reset the state to `initialState`
31
+ */
32
+ export default function useStateWithDeps<S>(
33
+ initialState: S | ((previousState?: S) => S),
34
+ deps: DependencyList,
35
+ ): [S, Dispatch<SetStateAction<S>>] {
36
+ // It would be possible to use useState instead of
37
+ // useRef to store the state, however this would
38
+ // trigger re-renders whenever the state is reset due
39
+ // to a change in dependencies. In order to avoid these
40
+ // re-renders, the state is stored in a ref and an
41
+ // update is triggered via forceUpdate below when necessary
42
+ const state = useRef(undefined as S);
43
+
44
+ const prevDeps = useRef(deps);
45
+ const isMounted = useRef(false);
46
+
47
+ // If first render, or if dependencies have changed since last time
48
+ if (!isMounted.current || !depsAreEqual(prevDeps.current, deps)) {
49
+ // Update state and deps
50
+ let nextState: S;
51
+ if (isFunction(initialState)) {
52
+ nextState = initialState(state.current);
53
+ } else {
54
+ nextState = initialState;
55
+ }
56
+ state.current = nextState;
57
+ prevDeps.current = deps;
58
+ isMounted.current = true;
59
+ }
60
+
61
+ const [forceUpdate] = useForceUpdate();
62
+
63
+ const updateState = useCallback(function updateState(
64
+ newState: S | ((previousState: S) => S),
65
+ ): void {
66
+ let nextState: S;
67
+ if (isFunction(newState)) {
68
+ nextState = newState(state.current);
69
+ } else {
70
+ nextState = newState;
71
+ }
72
+ if (!Object.is(state.current, nextState)) {
73
+ state.current = nextState;
74
+ forceUpdate();
75
+ }
76
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
77
+
78
+ return [state.current, updateState];
79
+ }
package/lib/index.ts CHANGED
@@ -1,3 +1,4 @@
1
- export { default as useDerivedState } from './hooks/useDerivedState';
2
1
  export { default as useEventListener } from './hooks/useEventListener';
3
2
  export { default as useForceUpdate } from './hooks/useForceUpdate';
3
+ export { default as useReducerWithDeps } from './hooks/useReducerWithDeps';
4
+ export { default as useStateWithDeps } from './hooks/useStateWithDeps';
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aweebit/react-essentials",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
5
  "repository": "github:aweebit/react-essentials",
6
6
  "main": "dist/index.js",
@@ -19,9 +19,11 @@
19
19
  "peerDependencies": {
20
20
  "react": ">=18.0.0 <20"
21
21
  },
22
+ "dependencies": {
23
+ "@types/react": "19.1.6"
24
+ },
22
25
  "devDependencies": {
23
26
  "@eslint/js": "^9.28.0",
24
- "@types/react": "^19.1.6",
25
27
  "eslint": "^9.28.0",
26
28
  "eslint-plugin-react-hooks": "^5.2.0",
27
29
  "husky": "^9.1.7",
@@ -29,7 +31,7 @@
29
31
  "prettier": "3.5.3",
30
32
  "rimraf": "^6.0.1",
31
33
  "typescript": "~5.8.3",
32
- "typescript-eslint": "^8.33.0"
34
+ "typescript-eslint": "^8.33.1"
33
35
  },
34
36
  "license": "MIT"
35
37
  }
@@ -1,42 +0,0 @@
1
- /**
2
- * @file Based on {@link https://github.com/peterjuras/use-state-with-deps}
3
- *
4
- * @license MIT
5
- *
6
- * Copyright (c) 2020 Peter Juras
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in all
16
- * copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- * SOFTWARE.
25
- */
26
- import { type DependencyList, type Dispatch, type SetStateAction } from 'react';
27
- /**
28
- * `useState` hook with an additional dependency array that resets
29
- * the state to the `initialState` param when the dependencies passed
30
- * in the `deps` array change.
31
- *
32
- * @param initialState
33
- * The state that will be set when the component mounts or the
34
- * dependencies change.
35
- *
36
- * It can also be a function which resolves to the state. If the state
37
- * is reset due to a change of dependencies, this function will be called with the previous
38
- * state (`undefined` for the first call upon mount).
39
- * @param deps Dependencies for this hook that resets the state to `initialState`
40
- */
41
- export default function useDerivedState<S>(initialState: S | ((previousState?: S) => S), deps: DependencyList): [S, Dispatch<SetStateAction<S>>];
42
- //# sourceMappingURL=useDerivedState.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useDerivedState.d.ts","sourceRoot":"","sources":["../../lib/hooks/useDerivedState.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAIf;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,CAAC,EACvC,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,CAsDlC"}
@@ -1,92 +0,0 @@
1
- /**
2
- * @file Based on {@link https://github.com/peterjuras/use-state-with-deps}
3
- *
4
- * @license MIT
5
- *
6
- * Copyright (c) 2020 Peter Juras
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in all
16
- * copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- * SOFTWARE.
25
- */
26
- import { useCallback, useRef, } from 'react';
27
- import { depsAreEqual, isFunction } from '../utils';
28
- import useForceUpdate from './useForceUpdate';
29
- /**
30
- * `useState` hook with an additional dependency array that resets
31
- * the state to the `initialState` param when the dependencies passed
32
- * in the `deps` array change.
33
- *
34
- * @param initialState
35
- * The state that will be set when the component mounts or the
36
- * dependencies change.
37
- *
38
- * It can also be a function which resolves to the state. If the state
39
- * is reset due to a change of dependencies, this function will be called with the previous
40
- * state (`undefined` for the first call upon mount).
41
- * @param deps Dependencies for this hook that resets the state to `initialState`
42
- */
43
- export default function useDerivedState(initialState, deps) {
44
- const isMounted = useRef(false);
45
- // Determine initial state
46
- let usableInitialState = null;
47
- if (!isMounted.current) {
48
- isMounted.current = true;
49
- if (isFunction(initialState)) {
50
- usableInitialState = initialState();
51
- }
52
- else {
53
- usableInitialState = initialState;
54
- }
55
- }
56
- // It would be possible to use useState instead of
57
- // useRef to store the state, however this would
58
- // trigger re-renders whenever the state is reset due
59
- // to a change in dependencies. In order to avoid these
60
- // re-renders, the state is stored in a ref and an
61
- // update is triggered via forceUpdate below when necessary
62
- const state = useRef(usableInitialState);
63
- // Check if dependencies have changed
64
- const prevDeps = useRef(deps);
65
- if (!depsAreEqual(prevDeps.current, deps)) {
66
- // Update state and deps
67
- let nextState;
68
- if (isFunction(initialState)) {
69
- nextState = initialState(state.current);
70
- }
71
- else {
72
- nextState = initialState;
73
- }
74
- state.current = nextState;
75
- prevDeps.current = deps;
76
- }
77
- const [forceUpdate] = useForceUpdate();
78
- const updateState = useCallback(function updateState(newState) {
79
- let nextState;
80
- if (isFunction(newState)) {
81
- nextState = newState(state.current);
82
- }
83
- else {
84
- nextState = newState;
85
- }
86
- if (!Object.is(state.current, nextState)) {
87
- state.current = nextState;
88
- forceUpdate();
89
- }
90
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
91
- return [state.current, updateState];
92
- }
@@ -1,108 +0,0 @@
1
- /**
2
- * @file Based on {@link https://github.com/peterjuras/use-state-with-deps}
3
- *
4
- * @license MIT
5
- *
6
- * Copyright (c) 2020 Peter Juras
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in all
16
- * copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- * SOFTWARE.
25
- */
26
-
27
- import {
28
- useCallback,
29
- useRef,
30
- type DependencyList,
31
- type Dispatch,
32
- type SetStateAction,
33
- } from 'react';
34
- import { depsAreEqual, isFunction } from '../utils';
35
- import useForceUpdate from './useForceUpdate';
36
-
37
- /**
38
- * `useState` hook with an additional dependency array that resets
39
- * the state to the `initialState` param when the dependencies passed
40
- * in the `deps` array change.
41
- *
42
- * @param initialState
43
- * The state that will be set when the component mounts or the
44
- * dependencies change.
45
- *
46
- * It can also be a function which resolves to the state. If the state
47
- * is reset due to a change of dependencies, this function will be called with the previous
48
- * state (`undefined` for the first call upon mount).
49
- * @param deps Dependencies for this hook that resets the state to `initialState`
50
- */
51
- export default function useDerivedState<S>(
52
- initialState: S | ((previousState?: S) => S),
53
- deps: DependencyList,
54
- ): [S, Dispatch<SetStateAction<S>>] {
55
- const isMounted = useRef(false);
56
-
57
- // Determine initial state
58
- let usableInitialState: S | null = null;
59
- if (!isMounted.current) {
60
- isMounted.current = true;
61
- if (isFunction(initialState)) {
62
- usableInitialState = initialState();
63
- } else {
64
- usableInitialState = initialState;
65
- }
66
- }
67
-
68
- // It would be possible to use useState instead of
69
- // useRef to store the state, however this would
70
- // trigger re-renders whenever the state is reset due
71
- // to a change in dependencies. In order to avoid these
72
- // re-renders, the state is stored in a ref and an
73
- // update is triggered via forceUpdate below when necessary
74
- const state = useRef(usableInitialState as S);
75
-
76
- // Check if dependencies have changed
77
- const prevDeps = useRef(deps);
78
- if (!depsAreEqual(prevDeps.current, deps)) {
79
- // Update state and deps
80
- let nextState: S;
81
- if (isFunction(initialState)) {
82
- nextState = initialState(state.current);
83
- } else {
84
- nextState = initialState;
85
- }
86
- state.current = nextState;
87
- prevDeps.current = deps;
88
- }
89
-
90
- const [forceUpdate] = useForceUpdate();
91
-
92
- const updateState = useCallback(function updateState(
93
- newState: S | ((previousState: S) => S),
94
- ): void {
95
- let nextState: S;
96
- if (isFunction(newState)) {
97
- nextState = newState(state.current);
98
- } else {
99
- nextState = newState;
100
- }
101
- if (!Object.is(state.current, nextState)) {
102
- state.current = nextState;
103
- forceUpdate();
104
- }
105
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
106
-
107
- return [state.current, updateState];
108
- }