react-reactive-val 2.0.4 → 2.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/README.md +73 -3
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +9 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
@@ -11,6 +11,7 @@ A lightweight, type-safe reactive value management library for React application
|
|
11
11
|
- 📦 **Tree-shakeable**: Only import what you need
|
12
12
|
- 🌳 **Multiple formats**: Supports ESM, CommonJS, and UMD
|
13
13
|
- 🌟 **Context Support**: Share reactive values efficiently through React Context
|
14
|
+
- 🎭 **Side Effects**: Register callbacks to run when values change
|
14
15
|
|
15
16
|
## Installation
|
16
17
|
|
@@ -41,6 +42,42 @@ function Counter() {
|
|
41
42
|
}
|
42
43
|
```
|
43
44
|
|
45
|
+
### Side Effects (New in v2.1.0)
|
46
|
+
|
47
|
+
You can register side effects to run whenever a reactive value changes:
|
48
|
+
|
49
|
+
```tsx
|
50
|
+
import { reallyReactiveVal, useReactiveEffect } from 'react-reactive-val';
|
51
|
+
|
52
|
+
// Create a shared reactive value
|
53
|
+
const [count, CountProvider] = reallyReactiveVal(0);
|
54
|
+
|
55
|
+
// Register an effect directly
|
56
|
+
const cleanup = count.effect(value => {
|
57
|
+
console.log(`Count changed to: ${value}`);
|
58
|
+
// Optional cleanup function
|
59
|
+
return () => console.log('Cleaning up previous effect');
|
60
|
+
});
|
61
|
+
|
62
|
+
// Later, you can clean up the effect
|
63
|
+
cleanup();
|
64
|
+
|
65
|
+
// Or use the hook in components for automatic cleanup
|
66
|
+
function CounterWithEffect() {
|
67
|
+
useReactiveEffect(count, value => {
|
68
|
+
console.log(`Count in component is: ${value}`);
|
69
|
+
return () => console.log('Component effect cleanup');
|
70
|
+
});
|
71
|
+
|
72
|
+
return (
|
73
|
+
<div>
|
74
|
+
<p>Count: {count()}</p>
|
75
|
+
<button onClick={() => count(prev => prev + 1)}>Increment</button>
|
76
|
+
</div>
|
77
|
+
);
|
78
|
+
}
|
79
|
+
```
|
80
|
+
|
44
81
|
### Sharing State Between Components
|
45
82
|
|
46
83
|
#### Using Direct Reference
|
@@ -65,7 +102,7 @@ function CounterButtons() {
|
|
65
102
|
}
|
66
103
|
```
|
67
104
|
|
68
|
-
#### Using Context
|
105
|
+
#### Using Context
|
69
106
|
|
70
107
|
```tsx
|
71
108
|
import { reallyReactiveVal } from 'react-reactive-val';
|
@@ -113,7 +150,7 @@ const value = useReactiveValue(initialValue);
|
|
113
150
|
|
114
151
|
### `reallyReactiveVal<T>(initialValue: T)`
|
115
152
|
|
116
|
-
Creates a standalone reactive value that can be used across components.
|
153
|
+
Creates a standalone reactive value that can be used across components. Returns a tuple containing the reactive value function, a Context Provider component, and a custom hook for accessing the value through context.
|
117
154
|
|
118
155
|
```tsx
|
119
156
|
const [value, Provider, useValue] = reallyReactiveVal(initialValue);
|
@@ -121,10 +158,27 @@ const [value, Provider, useValue] = reallyReactiveVal(initialValue);
|
|
121
158
|
|
122
159
|
- `initialValue`: The initial value of the reactive state
|
123
160
|
- Returns: A tuple containing:
|
124
|
-
1. A function that can both read and update the value
|
161
|
+
1. A function that can both read and update the value, with an additional `effect` method
|
125
162
|
2. A Context Provider component for wrapping consumers
|
126
163
|
3. A custom hook for accessing the value within the Context
|
127
164
|
|
165
|
+
### `useReactiveEffect<T>(reactiveValue: FnType<T>, callback: EffectCallback<T>)`
|
166
|
+
|
167
|
+
A React hook for managing side effects with reactive values.
|
168
|
+
|
169
|
+
```tsx
|
170
|
+
useReactiveEffect(value, newValue => {
|
171
|
+
console.log(`Value changed to: ${newValue}`);
|
172
|
+
return () => {
|
173
|
+
// Optional cleanup
|
174
|
+
};
|
175
|
+
});
|
176
|
+
```
|
177
|
+
|
178
|
+
- `reactiveValue`: The reactive value to watch
|
179
|
+
- `callback`: Function to run when the value changes
|
180
|
+
- The callback can optionally return a cleanup function
|
181
|
+
|
128
182
|
### Usage with Value Getter/Setter
|
129
183
|
|
130
184
|
```tsx
|
@@ -136,6 +190,14 @@ value(newValue);
|
|
136
190
|
|
137
191
|
// Update based on previous value
|
138
192
|
value(prev => computeNewValue(prev));
|
193
|
+
|
194
|
+
// Register a side effect
|
195
|
+
const cleanup = value.effect(newValue => {
|
196
|
+
console.log(`Value changed to: ${newValue}`);
|
197
|
+
return () => {
|
198
|
+
// Optional cleanup
|
199
|
+
};
|
200
|
+
});
|
139
201
|
```
|
140
202
|
|
141
203
|
## TypeScript Support
|
@@ -154,6 +216,14 @@ user(prev => ({ ...prev, name: 'John' })); // Type safe!
|
|
154
216
|
|
155
217
|
// With Context
|
156
218
|
const [userValue, UserProvider, useUser] = reallyReactiveVal<User | null>(null);
|
219
|
+
|
220
|
+
// With Effects
|
221
|
+
userValue.effect(user => {
|
222
|
+
console.log(`User updated: ${user?.name}`);
|
223
|
+
return () => {
|
224
|
+
// Cleanup is properly typed
|
225
|
+
};
|
226
|
+
});
|
157
227
|
```
|
158
228
|
|
159
229
|
## Contributing
|
package/dist/index.cjs.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
/*! For license information please see index.cjs.js.LICENSE.txt */
|
2
|
-
(()=>{"use strict";var e={698:(e,
|
2
|
+
(()=>{"use strict";var e={698:(e,t)=>{var r=Symbol.for("react.transitional.element");function n(e,t,n){var o=null;if(void 0!==n&&(o=""+n),void 0!==t.key&&(o=""+t.key),"key"in t)for(var u in n={},t)"key"!==u&&(n[u]=t[u]);else n=t;return t=n.ref,{$$typeof:r,type:e,key:o,ref:void 0!==t?t:null,props:n}}Symbol.for("react.fragment"),t.jsx=n},848:(e,t,r)=>{e.exports=r(698)}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var u=t[n]={exports:{}};return e[n](u,u.exports,r),u.exports}r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var n={};r.r(n),r.d(n,{Context:()=>i,default:()=>f,reallyReactiveVal:()=>c,useReactiveEffect:()=>l,useReactiveValueContext:()=>a});const o=require("react");var u=r(848);function f(e){return(0,o.useMemo)((function(){return c(e)}),[e])}var i=(0,o.createContext)(null),a=function(){return(0,o.useContext)(i)},c=function(e){var t=e,r=new Set,n=new Set,f=new Map,a=(0,o.memo)((function(){return(0,o.useSyncExternalStore)((function(e){return r.add(e),function(){return r.delete(e)}}),(function(){return t}))}));var c=Object.assign((function(e){if(void 0===e)return(0,u.jsx)(a,{});t!==(t="function"==typeof e?e(t):e)&&(n.forEach((function(e){var t=f.get(e);t&&t()})),n.forEach((function(e){var r=e(t);f.set(e,r)}))),r.forEach((function(e){e()}))}),{effect:function(e){n.add(e);var r=e(t);return f.set(e,r),function(){n.delete(e);var t=f.get(e);t&&t(),f.delete(e)}}});return[c,(0,o.memo)((function(e){var t=e.children;return(0,u.jsx)(i.Provider,{value:c,children:t})}))]},l=function(e,t){(0,o.useEffect)((function(){return e.effect(t)}),[e,t])};module.exports=n})();
|
package/dist/index.d.ts
CHANGED
@@ -1,9 +1,14 @@
|
|
1
|
-
import { type ReactNode, type ReactElement, type JSX } from 'react';
|
2
|
-
export default function useReactiveValue<T extends ReactNode>(initialValue: T):
|
1
|
+
import { type ReactNode, type ReactElement, PropsWithChildren, type JSX } from 'react';
|
2
|
+
export default function useReactiveValue<T extends ReactNode>(initialValue: T): readonly [FnType<T>, (props: PropsWithChildren) => JSX.Element];
|
3
3
|
type UpdaterType<T> = T | ((currVal: T) => T);
|
4
|
-
type
|
4
|
+
type EffectCallback<T> = (value: T) => void | (() => void);
|
5
|
+
type FnType<T> = {
|
6
|
+
<U extends UpdaterType<T> | unknown | undefined>(updater?: U): U extends UpdaterType<T> ? undefined : ReactElement;
|
7
|
+
effect: (callback: EffectCallback<T>) => () => void;
|
8
|
+
};
|
5
9
|
export declare const Context: import("react").Context<FnType<ReactElement<unknown, string | import("react").JSXElementConstructor<any>>> | null>;
|
6
10
|
export declare const useReactiveValueContext: () => FnType<ReactElement<unknown, string | import("react").JSXElementConstructor<any>>> | null;
|
7
|
-
export declare const reallyReactiveVal: <T extends ReactNode>(initialValue: T) =>
|
11
|
+
export declare const reallyReactiveVal: <T extends ReactNode>(initialValue: T) => readonly [FnType<T>, (props: PropsWithChildren) => JSX.Element];
|
12
|
+
export declare const useReactiveEffect: <T extends ReactNode>(reactiveValue: FnType<T>, callback: EffectCallback<T>) => void;
|
8
13
|
export {};
|
9
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,YAAY,
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,YAAY,EAMjB,iBAAiB,EACjB,KAAK,GAAG,EAET,MAAM,OAAO,CAAC;AAGf,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,CAAC,SAAS,SAAS,EAAE,YAAY,EAAE,CAAC,gCA4FlD,iBAAiB,KAAK,GAAG,CAAC,OAAO,EA1F3D;AAED,KAAK,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AAC9C,KAAK,cAAc,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;AAC3D,KAAK,MAAM,CAAC,CAAC,IAAI;IACf,CAAC,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,SAAS,EAC7C,OAAO,CAAC,EAAE,CAAC,GACV,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,YAAY,CAAC;IACvD,MAAM,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC;CACrD,CAAC;AAEF,eAAO,MAAM,OAAO,oHAAmD,CAAC;AAExE,eAAO,MAAM,uBAAuB,iGAEnC,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,SAAS,EAAE,cAAc,CAAC,kCAyE3C,iBAAiB,KAAK,GAAG,CAAC,OAAO,CAG3D,CAAC;AAGF,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,SAAS,EACnD,eAAe,MAAM,CAAC,CAAC,CAAC,EACxB,UAAU,cAAc,CAAC,CAAC,CAAC,SAK5B,CAAC"}
|
package/dist/index.esm.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
/*! For license information please see index.esm.js.LICENSE.txt */
|
2
|
-
import*as e from"react";var
|
2
|
+
import*as e from"react";var t={698:(e,t)=>{var r=Symbol.for("react.transitional.element");function n(e,t,n){var o=null;if(void 0!==n&&(o=""+n),void 0!==t.key&&(o=""+t.key),"key"in t)for(var u in n={},t)"key"!==u&&(n[u]=t[u]);else n=t;return t=n.ref,{$$typeof:r,type:e,key:o,ref:void 0!==t?t:null,props:n}}Symbol.for("react.fragment"),t.jsx=n},848:(e,t,r)=>{e.exports=r(698)}},r={};function n(e){var o=r[e];if(void 0!==o)return o.exports;var u=r[e]={exports:{}};return t[e](u,u.exports,n),u.exports}n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);const o=(e=>{var t={};return n.d(t,e),t})({createContext:()=>e.createContext,memo:()=>e.memo,useContext:()=>e.useContext,useEffect:()=>e.useEffect,useMemo:()=>e.useMemo,useSyncExternalStore:()=>e.useSyncExternalStore});var u=n(848);function f(e){return(0,o.useMemo)((function(){return i(e)}),[e])}var c=(0,o.createContext)(null),a=function(){return(0,o.useContext)(c)},i=function(e){var t=e,r=new Set,n=new Set,f=new Map,a=(0,o.memo)((function(){return(0,o.useSyncExternalStore)((function(e){return r.add(e),function(){return r.delete(e)}}),(function(){return t}))}));var i=Object.assign((function(e){if(void 0===e)return(0,u.jsx)(a,{});t!==(t="function"==typeof e?e(t):e)&&(n.forEach((function(e){var t=f.get(e);t&&t()})),n.forEach((function(e){var r=e(t);f.set(e,r)}))),r.forEach((function(e){e()}))}),{effect:function(e){n.add(e);var r=e(t);return f.set(e,r),function(){n.delete(e);var t=f.get(e);t&&t(),f.delete(e)}}});return[i,(0,o.memo)((function(e){var t=e.children;return(0,u.jsx)(c.Provider,{value:i,children:t})}))]},s=function(e,t){(0,o.useEffect)((function(){return e.effect(t)}),[e,t])};export{c as Context,f as default,i as reallyReactiveVal,s as useReactiveEffect,a as useReactiveValueContext};
|
package/dist/index.umd.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
/*! For license information please see index.umd.js.LICENSE.txt */
|
2
|
-
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define("ReactReactiveVal",["react"],t):"object"==typeof exports?exports.ReactReactiveVal=t(require("react")):e.ReactReactiveVal=t(e.React)}(this,(e=>(()=>{"use strict";var t={442:t=>{t.exports=e},698:(e,t)=>{var r=Symbol.for("react.transitional.element");function n(e,t,n){var o=null;if(void 0!==n&&(o=""+n),void 0!==t.key&&(o=""+t.key),"key"in t)for(var u in n={},t)"key"!==u&&(n[u]=t[u]);else n=t;return t=n.ref,{$$typeof:r,type:e,key:o,ref:void 0!==t?t:null,props:n}}Symbol.for("react.fragment"),t.jsx=n},848:(e,t,r)=>{e.exports=r(698)}},r={};function n(e){var o=r[e];if(void 0!==o)return o.exports;var u=r[e]={exports:{}};return t[e](u,u.exports,n),u.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};n.r(o),n.d(o,{Context:()=>c,default:()=>
|
2
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define("ReactReactiveVal",["react"],t):"object"==typeof exports?exports.ReactReactiveVal=t(require("react")):e.ReactReactiveVal=t(e.React)}(this,(e=>(()=>{"use strict";var t={442:t=>{t.exports=e},698:(e,t)=>{var r=Symbol.for("react.transitional.element");function n(e,t,n){var o=null;if(void 0!==n&&(o=""+n),void 0!==t.key&&(o=""+t.key),"key"in t)for(var u in n={},t)"key"!==u&&(n[u]=t[u]);else n=t;return t=n.ref,{$$typeof:r,type:e,key:o,ref:void 0!==t?t:null,props:n}}Symbol.for("react.fragment"),t.jsx=n},848:(e,t,r)=>{e.exports=r(698)}},r={};function n(e){var o=r[e];if(void 0!==o)return o.exports;var u=r[e]={exports:{}};return t[e](u,u.exports,n),u.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};n.r(o),n.d(o,{Context:()=>c,default:()=>f,reallyReactiveVal:()=>l,useReactiveEffect:()=>d,useReactiveValueContext:()=>i});var u=n(442),a=n(848);function f(e){return(0,u.useMemo)((function(){return l(e)}),[e])}var c=(0,u.createContext)(null),i=function(){return(0,u.useContext)(c)},l=function(e){var t=e,r=new Set,n=new Set,o=new Map,f=(0,u.memo)((function(){return(0,u.useSyncExternalStore)((function(e){return r.add(e),function(){return r.delete(e)}}),(function(){return t}))}));var i=Object.assign((function(e){if(void 0===e)return(0,a.jsx)(f,{});t!==(t="function"==typeof e?e(t):e)&&(n.forEach((function(e){var t=o.get(e);t&&t()})),n.forEach((function(e){var r=e(t);o.set(e,r)}))),r.forEach((function(e){e()}))}),{effect:function(e){n.add(e);var r=e(t);return o.set(e,r),function(){n.delete(e);var t=o.get(e);t&&t(),o.delete(e)}}});return[i,(0,u.memo)((function(e){var t=e.children;return(0,a.jsx)(c.Provider,{value:i,children:t})}))]},d=function(e,t){(0,u.useEffect)((function(){return e.effect(t)}),[e,t])};return o})()));
|
package/package.json
CHANGED