@apogeelabs/beacon-react-utils 0.3.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +96 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +42 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +39 -15
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +61 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -12
- package/dist/index.d.ts +0 -18
- package/dist/index.js +0 -36
- package/dist/index.js.map +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
let lodash = require("lodash");
|
|
30
|
+
lodash = __toESM(lodash);
|
|
31
|
+
let mobx = require("mobx");
|
|
32
|
+
let react = require("react");
|
|
33
|
+
|
|
34
|
+
//#region src/useStoreWatcher.ts
|
|
35
|
+
/**
|
|
36
|
+
* A custom React hook to watch for state changes in a beacon store.
|
|
37
|
+
*
|
|
38
|
+
* @template TState - The type of the store's state, extending BeaconState.
|
|
39
|
+
* @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
|
|
40
|
+
* @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
|
|
41
|
+
* @template T - The type returned by the selector function, inferred from the selector.
|
|
42
|
+
*
|
|
43
|
+
* @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
|
|
44
|
+
* @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
|
|
45
|
+
* @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
|
|
46
|
+
* @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
|
|
47
|
+
*/
|
|
48
|
+
function useStoreWatcher(store, selector, onChange, fireImmediately = false) {
|
|
49
|
+
const stableSelector = (0, react.useEffectEvent)(selector);
|
|
50
|
+
const stableOnChange = (0, react.useEffectEvent)(onChange);
|
|
51
|
+
(0, react.useEffect)(() => {
|
|
52
|
+
const disposer = (0, mobx.reaction)(() => {
|
|
53
|
+
return (0, mobx.toJS)(stableSelector(store));
|
|
54
|
+
}, (value, previousValue) => {
|
|
55
|
+
if (!previousValue || !lodash.default.isEqual(value, previousValue)) stableOnChange(value);
|
|
56
|
+
}, { fireImmediately });
|
|
57
|
+
store.registerCleanup(() => {
|
|
58
|
+
disposer();
|
|
59
|
+
});
|
|
60
|
+
return () => {
|
|
61
|
+
disposer();
|
|
62
|
+
};
|
|
63
|
+
}, [store, fireImmediately]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/useStoreState.ts
|
|
68
|
+
/**
|
|
69
|
+
* A React hook that subscribes to a Beacon store and returns a selected value as React state.
|
|
70
|
+
*
|
|
71
|
+
* Use this hook when you need a store value to participate in React's state lifecycle —
|
|
72
|
+
* for example, to drive React Query parameters, to pass into hooks that don't understand
|
|
73
|
+
* MobX observables, or to feed non-observer child components.
|
|
74
|
+
*
|
|
75
|
+
* For normal component rendering, prefer wrapping your component with `observer` from
|
|
76
|
+
* `mobx-react-lite` and reading store values directly. That's simpler and more performant.
|
|
77
|
+
*
|
|
78
|
+
* @template TState - The type of the store's state, extending BeaconState.
|
|
79
|
+
* @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.
|
|
80
|
+
* @template TActions - The type of the store's actions, extending BeaconActions<TState>.
|
|
81
|
+
* @template T - The type returned by the selector function, inferred from the selector.
|
|
82
|
+
*
|
|
83
|
+
* @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
|
|
84
|
+
* @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.
|
|
85
|
+
* @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.
|
|
86
|
+
*/
|
|
87
|
+
function useStoreState(store, selector) {
|
|
88
|
+
const [value, setValue] = (0, react.useState)(() => (0, mobx.toJS)(selector(store)));
|
|
89
|
+
useStoreWatcher(store, selector, setValue);
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
//#endregion
|
|
94
|
+
exports.useStoreState = useStoreState;
|
|
95
|
+
exports.useStoreWatcher = useStoreWatcher;
|
|
96
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["_"],"sources":["../src/useStoreWatcher.ts","../src/useStoreState.ts"],"sourcesContent":["import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport _ from \"lodash\";\nimport { reaction, toJS } from \"mobx\";\nimport { useEffect, useEffectEvent } from \"react\";\n\n/**\n * A custom React hook to watch for state changes in a beacon store.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.\n * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.\n * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.\n */\nexport function useStoreWatcher<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n onChange: (value: T) => void,\n fireImmediately: boolean = false\n): void {\n // Use useEffectEvent to wrap callbacks so they don't need to be in the dependency array\n // This prevents unnecessary re-runs when consumers pass inline functions\n const stableSelector = useEffectEvent(selector);\n const stableOnChange = useEffectEvent(onChange);\n\n useEffect(() => {\n const disposer = reaction(\n () => {\n // toJS strips MobX observable wrappers so React sees plain values\n return toJS(stableSelector(store));\n },\n (value, previousValue) => {\n // MobX selectors can return new object references even when the underlying\n // data hasn't changed. Deep comparison prevents spurious re-renders.\n if (!previousValue || !_.isEqual(value, previousValue)) {\n stableOnChange(value);\n }\n },\n { fireImmediately }\n );\n\n // If the store is disposed externally, clean up the reaction too\n store.registerCleanup(() => {\n disposer();\n });\n\n return () => {\n disposer();\n };\n // stableSelector and stableOnChange are omitted from deps intentionally —\n // useEffectEvent keeps them stable across renders without needing to re-run the effect\n }, [store, fireImmediately]);\n}\n\nexport default useStoreWatcher;\n","import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport { toJS } from \"mobx\";\nimport { useState } from \"react\";\nimport { useStoreWatcher } from \"./useStoreWatcher\";\n\n/**\n * A React hook that subscribes to a Beacon store and returns a selected value as React state.\n *\n * Use this hook when you need a store value to participate in React's state lifecycle —\n * for example, to drive React Query parameters, to pass into hooks that don't understand\n * MobX observables, or to feed non-observer child components.\n *\n * For normal component rendering, prefer wrapping your component with `observer` from\n * `mobx-react-lite` and reading store values directly. That's simpler and more performant.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.\n * @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.\n */\nexport function useStoreState<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n): T {\n // Initializer function so the selector only runs once on mount, not on every render\n const [value, setValue] = useState<T>(() => toJS(selector(store)));\n\n // Wires MobX reactivity to React state — store changes call setValue, triggering a re-render\n useStoreWatcher(store, selector, setValue);\n\n return value;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBA,SAAgB,gBAMZ,OACA,UACA,UACA,kBAA2B,OACvB;CAGJ,MAAM,2CAAgC,SAAS;CAC/C,MAAM,2CAAgC,SAAS;AAE/C,4BAAgB;EACZ,MAAM,oCACI;AAEF,yBAAY,eAAe,MAAM,CAAC;MAErC,OAAO,kBAAkB;AAGtB,OAAI,CAAC,iBAAiB,CAACA,eAAE,QAAQ,OAAO,cAAc,CAClD,gBAAe,MAAM;KAG7B,EAAE,iBAAiB,CACtB;AAGD,QAAM,sBAAsB;AACxB,aAAU;IACZ;AAEF,eAAa;AACT,aAAU;;IAIf,CAAC,OAAO,gBAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;ACpChC,SAAgB,cAMZ,OACA,UACC;CAED,MAAM,CAAC,OAAO,qDAAmC,SAAS,MAAM,CAAC,CAAC;AAGlE,iBAAgB,OAAO,UAAU,SAAS;AAE1C,QAAO"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { BeaconActions, BeaconDerived, BeaconState, Store } from "@apogeelabs/beacon";
|
|
2
|
+
|
|
3
|
+
//#region src/useStoreWatcher.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A custom React hook to watch for state changes in a beacon store.
|
|
6
|
+
*
|
|
7
|
+
* @template TState - The type of the store's state, extending BeaconState.
|
|
8
|
+
* @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
|
|
9
|
+
* @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
|
|
10
|
+
* @template T - The type returned by the selector function, inferred from the selector.
|
|
11
|
+
*
|
|
12
|
+
* @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
|
|
13
|
+
* @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
|
|
14
|
+
* @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
|
|
15
|
+
* @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
|
|
16
|
+
*/
|
|
17
|
+
declare function useStoreWatcher<TState extends BeaconState, TDerived extends BeaconDerived<TState>, TActions extends BeaconActions<TState>, T>(store: Store<TState, TDerived, TActions>, selector: (store: Store<TState, TDerived, TActions>) => T, onChange: (value: T) => void, fireImmediately?: boolean): void;
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/useStoreState.d.ts
|
|
20
|
+
/**
|
|
21
|
+
* A React hook that subscribes to a Beacon store and returns a selected value as React state.
|
|
22
|
+
*
|
|
23
|
+
* Use this hook when you need a store value to participate in React's state lifecycle —
|
|
24
|
+
* for example, to drive React Query parameters, to pass into hooks that don't understand
|
|
25
|
+
* MobX observables, or to feed non-observer child components.
|
|
26
|
+
*
|
|
27
|
+
* For normal component rendering, prefer wrapping your component with `observer` from
|
|
28
|
+
* `mobx-react-lite` and reading store values directly. That's simpler and more performant.
|
|
29
|
+
*
|
|
30
|
+
* @template TState - The type of the store's state, extending BeaconState.
|
|
31
|
+
* @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.
|
|
32
|
+
* @template TActions - The type of the store's actions, extending BeaconActions<TState>.
|
|
33
|
+
* @template T - The type returned by the selector function, inferred from the selector.
|
|
34
|
+
*
|
|
35
|
+
* @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
|
|
36
|
+
* @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.
|
|
37
|
+
* @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.
|
|
38
|
+
*/
|
|
39
|
+
declare function useStoreState<TState extends BeaconState, TDerived extends BeaconDerived<TState>, TActions extends BeaconActions<TState>, T>(store: Store<TState, TDerived, TActions>, selector: (store: Store<TState, TDerived, TActions>) => T): T;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { useStoreState, useStoreWatcher };
|
|
42
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/useStoreWatcher.ts","../src/useStoreState.ts"],"mappings":";;;;;AAkBA;;;;;;;;;;;iBAAgB,eAAA,gBACG,WAAA,mBACE,aAAA,CAAc,MAAA,oBACd,aAAA,CAAc,MAAA,KAAA,CAG/B,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,GAC/B,QAAA,GAAW,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,MAAc,CAAA,EACxD,QAAA,GAAW,KAAA,EAAO,CAAA,WAClB,eAAA;;;;;AATJ;;;;;;;;;;;;;;;;;iBCMgB,aAAA,gBACG,WAAA,mBACE,aAAA,CAAc,MAAA,oBACd,aAAA,CAAc,MAAA,KAAA,CAG/B,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,GAC/B,QAAA,GAAW,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,MAAc,CAAA,GACzD,CAAA"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,18 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BeaconActions, BeaconDerived, BeaconState, Store } from "@apogeelabs/beacon";
|
|
2
2
|
|
|
3
|
+
//#region src/useStoreWatcher.d.ts
|
|
3
4
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
* A custom React hook to watch for state changes in a beacon store.
|
|
6
|
+
*
|
|
7
|
+
* @template TState - The type of the store's state, extending BeaconState.
|
|
8
|
+
* @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
|
|
9
|
+
* @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
|
|
10
|
+
* @template T - The type returned by the selector function, inferred from the selector.
|
|
11
|
+
*
|
|
12
|
+
* @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
|
|
13
|
+
* @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
|
|
14
|
+
* @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
|
|
15
|
+
* @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
|
|
16
|
+
*/
|
|
16
17
|
declare function useStoreWatcher<TState extends BeaconState, TDerived extends BeaconDerived<TState>, TActions extends BeaconActions<TState>, T>(store: Store<TState, TDerived, TActions>, selector: (store: Store<TState, TDerived, TActions>) => T, onChange: (value: T) => void, fireImmediately?: boolean): void;
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/useStoreState.d.ts
|
|
20
|
+
/**
|
|
21
|
+
* A React hook that subscribes to a Beacon store and returns a selected value as React state.
|
|
22
|
+
*
|
|
23
|
+
* Use this hook when you need a store value to participate in React's state lifecycle —
|
|
24
|
+
* for example, to drive React Query parameters, to pass into hooks that don't understand
|
|
25
|
+
* MobX observables, or to feed non-observer child components.
|
|
26
|
+
*
|
|
27
|
+
* For normal component rendering, prefer wrapping your component with `observer` from
|
|
28
|
+
* `mobx-react-lite` and reading store values directly. That's simpler and more performant.
|
|
29
|
+
*
|
|
30
|
+
* @template TState - The type of the store's state, extending BeaconState.
|
|
31
|
+
* @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.
|
|
32
|
+
* @template TActions - The type of the store's actions, extending BeaconActions<TState>.
|
|
33
|
+
* @template T - The type returned by the selector function, inferred from the selector.
|
|
34
|
+
*
|
|
35
|
+
* @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
|
|
36
|
+
* @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.
|
|
37
|
+
* @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.
|
|
38
|
+
*/
|
|
39
|
+
declare function useStoreState<TState extends BeaconState, TDerived extends BeaconDerived<TState>, TActions extends BeaconActions<TState>, T>(store: Store<TState, TDerived, TActions>, selector: (store: Store<TState, TDerived, TActions>) => T): T;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { useStoreState, useStoreWatcher };
|
|
42
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/useStoreWatcher.ts","../src/useStoreState.ts"],"mappings":";;;;;AAkBA;;;;;;;;;;;iBAAgB,eAAA,gBACG,WAAA,mBACE,aAAA,CAAc,MAAA,oBACd,aAAA,CAAc,MAAA,KAAA,CAG/B,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,GAC/B,QAAA,GAAW,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,MAAc,CAAA,EACxD,QAAA,GAAW,KAAA,EAAO,CAAA,WAClB,eAAA;;;;;AATJ;;;;;;;;;;;;;;;;;iBCMgB,aAAA,gBACG,WAAA,mBACE,aAAA,CAAc,MAAA,oBACd,aAAA,CAAc,MAAA,KAAA,CAG/B,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,GAC/B,QAAA,GAAW,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,QAAA,EAAU,QAAA,MAAc,CAAA,GACzD,CAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,30 +1,66 @@
|
|
|
1
|
-
import _ from
|
|
2
|
-
import { reaction, toJS } from
|
|
3
|
-
import { useEffect } from
|
|
1
|
+
import _ from "lodash";
|
|
2
|
+
import { reaction, toJS } from "mobx";
|
|
3
|
+
import { useEffect, useEffectEvent, useState } from "react";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
//#region src/useStoreWatcher.ts
|
|
6
|
+
/**
|
|
7
|
+
* A custom React hook to watch for state changes in a beacon store.
|
|
8
|
+
*
|
|
9
|
+
* @template TState - The type of the store's state, extending BeaconState.
|
|
10
|
+
* @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
|
|
11
|
+
* @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
|
|
12
|
+
* @template T - The type returned by the selector function, inferred from the selector.
|
|
13
|
+
*
|
|
14
|
+
* @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
|
|
15
|
+
* @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
|
|
16
|
+
* @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
|
|
17
|
+
* @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
|
|
18
|
+
*/
|
|
6
19
|
function useStoreWatcher(store, selector, onChange, fireImmediately = false) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return () => {
|
|
23
|
-
disposer();
|
|
24
|
-
};
|
|
25
|
-
}, [store, selector, onChange, fireImmediately]);
|
|
20
|
+
const stableSelector = useEffectEvent(selector);
|
|
21
|
+
const stableOnChange = useEffectEvent(onChange);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const disposer = reaction(() => {
|
|
24
|
+
return toJS(stableSelector(store));
|
|
25
|
+
}, (value, previousValue) => {
|
|
26
|
+
if (!previousValue || !_.isEqual(value, previousValue)) stableOnChange(value);
|
|
27
|
+
}, { fireImmediately });
|
|
28
|
+
store.registerCleanup(() => {
|
|
29
|
+
disposer();
|
|
30
|
+
});
|
|
31
|
+
return () => {
|
|
32
|
+
disposer();
|
|
33
|
+
};
|
|
34
|
+
}, [store, fireImmediately]);
|
|
26
35
|
}
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
//#
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/useStoreState.ts
|
|
39
|
+
/**
|
|
40
|
+
* A React hook that subscribes to a Beacon store and returns a selected value as React state.
|
|
41
|
+
*
|
|
42
|
+
* Use this hook when you need a store value to participate in React's state lifecycle —
|
|
43
|
+
* for example, to drive React Query parameters, to pass into hooks that don't understand
|
|
44
|
+
* MobX observables, or to feed non-observer child components.
|
|
45
|
+
*
|
|
46
|
+
* For normal component rendering, prefer wrapping your component with `observer` from
|
|
47
|
+
* `mobx-react-lite` and reading store values directly. That's simpler and more performant.
|
|
48
|
+
*
|
|
49
|
+
* @template TState - The type of the store's state, extending BeaconState.
|
|
50
|
+
* @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.
|
|
51
|
+
* @template TActions - The type of the store's actions, extending BeaconActions<TState>.
|
|
52
|
+
* @template T - The type returned by the selector function, inferred from the selector.
|
|
53
|
+
*
|
|
54
|
+
* @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
|
|
55
|
+
* @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.
|
|
56
|
+
* @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.
|
|
57
|
+
*/
|
|
58
|
+
function useStoreState(store, selector) {
|
|
59
|
+
const [value, setValue] = useState(() => toJS(selector(store)));
|
|
60
|
+
useStoreWatcher(store, selector, setValue);
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
export { useStoreState, useStoreWatcher };
|
|
30
66
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/useStoreWatcher.ts","../src/useStoreState.ts"],"sourcesContent":["import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport _ from \"lodash\";\nimport { reaction, toJS } from \"mobx\";\nimport { useEffect, useEffectEvent } from \"react\";\n\n/**\n * A custom React hook to watch for state changes in a beacon store.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.\n * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.\n * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.\n */\nexport function useStoreWatcher<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n onChange: (value: T) => void,\n fireImmediately: boolean = false\n): void {\n // Use useEffectEvent to wrap callbacks so they don't need to be in the dependency array\n // This prevents unnecessary re-runs when consumers pass inline functions\n const stableSelector = useEffectEvent(selector);\n const stableOnChange = useEffectEvent(onChange);\n\n useEffect(() => {\n const disposer = reaction(\n () => {\n // toJS strips MobX observable wrappers so React sees plain values\n return toJS(stableSelector(store));\n },\n (value, previousValue) => {\n // MobX selectors can return new object references even when the underlying\n // data hasn't changed. Deep comparison prevents spurious re-renders.\n if (!previousValue || !_.isEqual(value, previousValue)) {\n stableOnChange(value);\n }\n },\n { fireImmediately }\n );\n\n // If the store is disposed externally, clean up the reaction too\n store.registerCleanup(() => {\n disposer();\n });\n\n return () => {\n disposer();\n };\n // stableSelector and stableOnChange are omitted from deps intentionally —\n // useEffectEvent keeps them stable across renders without needing to re-run the effect\n }, [store, fireImmediately]);\n}\n\nexport default useStoreWatcher;\n","import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport { toJS } from \"mobx\";\nimport { useState } from \"react\";\nimport { useStoreWatcher } from \"./useStoreWatcher\";\n\n/**\n * A React hook that subscribes to a Beacon store and returns a selected value as React state.\n *\n * Use this hook when you need a store value to participate in React's state lifecycle —\n * for example, to drive React Query parameters, to pass into hooks that don't understand\n * MobX observables, or to feed non-observer child components.\n *\n * For normal component rendering, prefer wrapping your component with `observer` from\n * `mobx-react-lite` and reading store values directly. That's simpler and more performant.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the value to track.\n * @returns {T} The current value of the selected store slice, kept in sync via MobX reaction.\n */\nexport function useStoreState<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n): T {\n // Initializer function so the selector only runs once on mount, not on every render\n const [value, setValue] = useState<T>(() => toJS(selector(store)));\n\n // Wires MobX reactivity to React state — store changes call setValue, triggering a re-render\n useStoreWatcher(store, selector, setValue);\n\n return value;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,SAAgB,gBAMZ,OACA,UACA,UACA,kBAA2B,OACvB;CAGJ,MAAM,iBAAiB,eAAe,SAAS;CAC/C,MAAM,iBAAiB,eAAe,SAAS;AAE/C,iBAAgB;EACZ,MAAM,WAAW,eACP;AAEF,UAAO,KAAK,eAAe,MAAM,CAAC;MAErC,OAAO,kBAAkB;AAGtB,OAAI,CAAC,iBAAiB,CAAC,EAAE,QAAQ,OAAO,cAAc,CAClD,gBAAe,MAAM;KAG7B,EAAE,iBAAiB,CACtB;AAGD,QAAM,sBAAsB;AACxB,aAAU;IACZ;AAEF,eAAa;AACT,aAAU;;IAIf,CAAC,OAAO,gBAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;ACpChC,SAAgB,cAMZ,OACA,UACC;CAED,MAAM,CAAC,OAAO,YAAY,eAAkB,KAAK,SAAS,MAAM,CAAC,CAAC;AAGlE,iBAAgB,OAAO,UAAU,SAAS;AAE1C,QAAO"}
|
package/package.json
CHANGED
|
@@ -6,20 +6,20 @@
|
|
|
6
6
|
"name": "Jim Cowart"
|
|
7
7
|
}
|
|
8
8
|
],
|
|
9
|
-
"version": "
|
|
9
|
+
"version": "1.1.0",
|
|
10
10
|
"license": "ISC",
|
|
11
|
-
"description": "
|
|
11
|
+
"description": "React hooks and utilities for Beacon stores",
|
|
12
12
|
"engines": {
|
|
13
13
|
"node": ">=18"
|
|
14
14
|
},
|
|
15
|
-
"main": "dist/index.
|
|
15
|
+
"main": "dist/index.cjs",
|
|
16
16
|
"module": "dist/index.mjs",
|
|
17
|
-
"types": "dist/index.d.
|
|
17
|
+
"types": "dist/index.d.cts",
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
|
-
"
|
|
20
|
+
"types": "./dist/index.d.mts",
|
|
21
21
|
"import": "./dist/index.mjs",
|
|
22
|
-
"
|
|
22
|
+
"require": "./dist/index.cjs"
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
@@ -39,13 +39,13 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"lodash": "4.17.16",
|
|
41
41
|
"mobx": "^6.13.7",
|
|
42
|
-
"react": "19.
|
|
43
|
-
"@apogeelabs/beacon": "
|
|
42
|
+
"react": "^19.2.3",
|
|
43
|
+
"@apogeelabs/beacon": "1.1.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/jest": "^29.5.5",
|
|
47
47
|
"@types/lodash": "4.17.16",
|
|
48
|
-
"@types/react": "19.
|
|
48
|
+
"@types/react": "^19.2.3",
|
|
49
49
|
"eslint": "^8.0.1",
|
|
50
50
|
"eslint-config-standard": "^17.1.0",
|
|
51
51
|
"eslint-plugin-import": "^2.25.2",
|
|
@@ -53,12 +53,12 @@
|
|
|
53
53
|
"eslint-plugin-promise": "^6.0.0",
|
|
54
54
|
"jest": "^29.7.0",
|
|
55
55
|
"ts-jest": "^29.1.1",
|
|
56
|
-
"
|
|
56
|
+
"tsdown": "^0.20.3",
|
|
57
57
|
"typescript": "^5.2.2"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
|
-
"dev": "
|
|
61
|
-
"build": "
|
|
60
|
+
"dev": "tsdown --watch",
|
|
61
|
+
"build": "tsdown",
|
|
62
62
|
"test": "jest",
|
|
63
63
|
"test:watch": "jest --watch --collect-coverage",
|
|
64
64
|
"lint": "eslint --config ../../.eslintrc.js 'src/**/*.{ts,tsx}'"
|
package/dist/index.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { BeaconState, BeaconDerived, BeaconActions, Store } from '@apogeelabs/beacon';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* A custom React hook to watch for state changes in a beacon store.
|
|
5
|
-
*
|
|
6
|
-
* @template TState - The type of the store's state, extending BeaconState.
|
|
7
|
-
* @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.
|
|
8
|
-
* @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.
|
|
9
|
-
* @template T - The type returned by the selector function, inferred from the selector.
|
|
10
|
-
*
|
|
11
|
-
* @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.
|
|
12
|
-
* @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.
|
|
13
|
-
* @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.
|
|
14
|
-
* @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.
|
|
15
|
-
*/
|
|
16
|
-
declare function useStoreWatcher<TState extends BeaconState, TDerived extends BeaconDerived<TState>, TActions extends BeaconActions<TState>, T>(store: Store<TState, TDerived, TActions>, selector: (store: Store<TState, TDerived, TActions>) => T, onChange: (value: T) => void, fireImmediately?: boolean): void;
|
|
17
|
-
|
|
18
|
-
export { useStoreWatcher };
|
package/dist/index.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var _ = require('lodash');
|
|
4
|
-
var mobx = require('mobx');
|
|
5
|
-
var react = require('react');
|
|
6
|
-
|
|
7
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
-
|
|
9
|
-
var ___default = /*#__PURE__*/_interopDefault(_);
|
|
10
|
-
|
|
11
|
-
// src/useStoreWatcher.ts
|
|
12
|
-
function useStoreWatcher(store, selector, onChange, fireImmediately = false) {
|
|
13
|
-
react.useEffect(() => {
|
|
14
|
-
const disposer = mobx.reaction(
|
|
15
|
-
() => {
|
|
16
|
-
return mobx.toJS(selector(store));
|
|
17
|
-
},
|
|
18
|
-
(value, previousValue) => {
|
|
19
|
-
if (!previousValue || !___default.default.isEqual(value, previousValue)) {
|
|
20
|
-
onChange(value);
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
{ fireImmediately }
|
|
24
|
-
);
|
|
25
|
-
store.registerCleanup(() => {
|
|
26
|
-
disposer();
|
|
27
|
-
});
|
|
28
|
-
return () => {
|
|
29
|
-
disposer();
|
|
30
|
-
};
|
|
31
|
-
}, [store, selector, onChange, fireImmediately]);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
exports.useStoreWatcher = useStoreWatcher;
|
|
35
|
-
//# sourceMappingURL=out.js.map
|
|
36
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useStoreWatcher.ts"],"names":[],"mappings":";AACA,OAAO,OAAO;AACd,SAAS,UAAU,YAAY;AAC/B,SAAS,iBAAiB;AAenB,SAAS,gBAMZ,OACA,UACA,UACA,kBAA2B,OACvB;AACJ,YAAU,MAAM;AAEZ,UAAM,WAAW;AAAA,MACb,MAAM;AAEF,eAAO,KAAK,SAAS,KAAK,CAAC;AAAA,MAC/B;AAAA,MACA,CAAC,OAAO,kBAAkB;AAEtB,YAAI,CAAC,iBAAiB,CAAC,EAAE,QAAQ,OAAO,aAAa,GAAG;AACpD,mBAAS,KAAK;AAAA,QAClB;AAAA,MACJ;AAAA,MACA,EAAE,gBAAgB;AAAA,IACtB;AAGA,UAAM,gBAAgB,MAAM;AACxB,eAAS;AAAA,IACb,CAAC;AAGD,WAAO,MAAM;AACT,eAAS;AAAA,IACb;AAAA,EACJ,GAAG,CAAC,OAAO,UAAU,UAAU,eAAe,CAAC;AACnD","sourcesContent":["import type { BeaconActions, BeaconDerived, BeaconState, Store } from \"@apogeelabs/beacon\";\nimport _ from \"lodash\";\nimport { reaction, toJS } from \"mobx\";\nimport { useEffect } from \"react\";\n\n/**\n * A custom React hook to watch for state changes in a beacon store.\n *\n * @template TState - The type of the store's state, extending BeaconState.\n * @template TDerived - The type of the store's derived values, extending BeaconDerived<TState>. If you don't have derived values, use EmptyDerived<TState>.\n * @template TActions - The type of the store's actions, extending BeaconActions<TState>. If you don't have actions, use EmptyActions.\n * @template T - The type returned by the selector function, inferred from the selector.\n *\n * @param {Store<TState, TDerived, TActions>} store - The Beacon store instance.\n * @param {(store: Store<TState, TDerived, TActions>) => T} selector - A function that extracts the part of the store to watch.\n * @param {(value: T) => void} onChange - A callback invoked with the new value when the selected state changes.\n * @param {boolean} [fireImmediately=false] - Whether to invoke onChange with the initial value.\n */\nexport function useStoreWatcher<\n TState extends BeaconState,\n TDerived extends BeaconDerived<TState>,\n TActions extends BeaconActions<TState>,\n T,\n>(\n store: Store<TState, TDerived, TActions>,\n selector: (store: Store<TState, TDerived, TActions>) => T,\n onChange: (value: T) => void,\n fireImmediately: boolean = false\n): void {\n useEffect(() => {\n // Set up a MobX reaction to watch the selected state\n const disposer = reaction(\n () => {\n // Convert to plain JS to strip MobX observable properties\n return toJS(selector(store));\n },\n (value, previousValue) => {\n // Only trigger if the value actually changed using deep comparison\n if (!previousValue || !_.isEqual(value, previousValue)) {\n onChange(value);\n }\n },\n { fireImmediately }\n );\n\n // Register the disposer with the store for cleanup\n store.registerCleanup(() => {\n disposer();\n });\n\n // Cleanup when the component unmounts or dependencies change\n return () => {\n disposer();\n };\n }, [store, selector, onChange, fireImmediately]);\n}\n\nexport default useStoreWatcher;\n"]}
|