state-jet 2.0.16 → 2.0.17

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 (2) hide show
  1. package/README.md +263 -45
  2. package/package.json +23 -2
package/README.md CHANGED
@@ -1,7 +1,41 @@
1
+ [![npm](https://img.shields.io/npm/v/state-jet.svg)](https://www.npmjs.com/package/state-jet)
2
+ [![npm](https://img.shields.io/npm/dt/state-jet.svg)](https://npm-stat.com/charts.html?package=state-jet)
3
+ [![GitHub issues](https://img.shields.io/github/issues/venkateshsundaram/state-jet.svg)](https://github.com/venkateshsundaram/state-jet/issues)
4
+
1
5
  A zero-boilerplate, ultra-fast global state management library for React.
2
6
 
3
7
  For more details, see [here](https://statejet.netlify.app).
4
8
 
9
+ ## Table of Contents
10
+
11
+ - [🚀 Why state-jet?](#🚀-why-state-jet?)
12
+ - [Documentation](#documentation)
13
+ - [🛠 Installation](#🛠-installation)
14
+ - [GlobalState](#globalstate)
15
+ - [Create GlobalState](#create-globalstate)
16
+ - [Binding Global State to a Component](#binding-global-state-to-a-component)
17
+ - [Slices](#slices)
18
+ - [Create Slice](#create-slice)
19
+ - [Store](#store)
20
+ - [Create Store](#create-store)
21
+ - [Binding Global State to a Component](#binding-global-state-to-a-component)
22
+ - [Middlewares](#middlewares)
23
+ - [Logger Middleware](#logger-middleware)
24
+ - [Reducer Middleware](#reducer-middleware)
25
+ - [Debounce Middleware](#debounce-middleware)
26
+ - [Optimistic Middleware](#optimistic-middleware)
27
+ - [Custom Middleware](#custom-middleware)
28
+ - [Typescript Usage](#typescript-usage)
29
+ - [Why state-jet Is More Advanced Than Zustand](#why-state-jet-is-more-advanced-than-zustand)
30
+ - [FAQ](#faq)
31
+ - [Conclusion](#conclusion)
32
+ - [⚡ Comparison Table](#⚡-comparison-table)
33
+ - [Comparison with other libraries](#comparison-with-other-libraries)
34
+ - [Contributing](#contributing)
35
+ - [Publishing](#publishing)
36
+ - [Feedbacks and Issues](#feedbacks-and-issues)
37
+ - [License](#license)
38
+
5
39
  ## 🚀 Why state-jet?
6
40
 
7
41
  - ✅ **No Context, No Providers** – Works outside React, reducing unnecessary re-renders.
@@ -47,14 +81,31 @@ The `useStateGlobal` hook is the simplest entry point to State-Jet. It allows yo
47
81
 
48
82
  ### Create GlobalState
49
83
 
50
- ```tsx
84
+ ```ts
85
+ // file: src/store/index.ts
86
+
51
87
  import { useStateGlobal } from "state-jet";
52
88
 
53
- const counter = useStateGlobal("counter", 0);
89
+ export const counterState = useStateGlobal("counter", 0);
90
+ ```
91
+
92
+ ### Binding Global State to a Component
54
93
 
55
- function Counter() {
56
- const count = counter.useState();
57
- return <button onClick={() => counter.set(count + 1)}>Count: {count}</button>;
94
+ ```tsx
95
+ // file: src/components/Counter.tsx
96
+
97
+ import { counterState } from "../store";
98
+
99
+ export default function Counter() {
100
+ const count = counterState.useState() as number;
101
+
102
+ return (
103
+ <div>
104
+ <h1>Counter: {count}</h1>
105
+ <button onClick={() => counterState.set(count - 1)}>Decrement</button>
106
+ <button onClick={() => counterState.set(count + 1)}>Increment</button>
107
+ </div>
108
+ );
58
109
  }
59
110
  ```
60
111
 
@@ -66,7 +117,9 @@ Each slice can contain multiple state values, each identified by a unique key wi
66
117
 
67
118
  ### Create Slice
68
119
 
69
- ```tsx
120
+ ```ts
121
+ // file: src/store/slices.ts
122
+
70
123
  import { useSlice } from "state-jet";
71
124
 
72
125
  const productSlice = useSlice("products");
@@ -82,16 +135,76 @@ The `useStore` hook serves as a mechanism to group related slices of state into
82
135
 
83
136
  ### Create Store
84
137
 
85
- ```tsx
138
+ ```ts
139
+ // file: src/store/index.ts
140
+
86
141
  import { useStore } from "state-jet";
87
142
  import { useProductSlice, useCartSlice } from "./slices";
88
143
 
144
+ /**
145
+ * Ecommerce store with product and cart slices
146
+ */
89
147
  const initializer: any = () => ({
90
148
  products: useProductSlice(),
91
149
  cart: useCartSlice(),
92
150
  });
93
151
 
94
- export const store = () => useStore(initializer);
152
+ export const useEcommerceStore = () => useStore(initializer);
153
+ ```
154
+
155
+ ### Binding Global State to a Component
156
+
157
+ ```tsx
158
+ // file: src/components/ProductList.tsx
159
+
160
+ import { useEcommerceStore } from "../store";
161
+
162
+ type ProductType = {
163
+ name: string,
164
+ price: number
165
+ }
166
+
167
+ type CartType = {
168
+ name: string,
169
+ price: number,
170
+ count: number
171
+ }
172
+
173
+ export const ProductList = () => {
174
+ const store = useEcommerceStore();
175
+ const products: any = store.products;
176
+ const cart: any = store.cart;
177
+ const productItems = products.useState() as ProductType[];
178
+ const cartItems = cart.useState() as CartType[];
179
+
180
+ const addToCart = (product: ProductType) => {
181
+ if (cartItems.some((cartItem: CartType) => cartItem.name === product.name)) {
182
+ cart.set(cartItems.map((cartItem: CartType) => {
183
+ if (cartItem.name === product.name) {
184
+ return { ...cartItem, count: (cartItem.count || 0) + 1 };
185
+ }
186
+ return cartItem;
187
+ }));
188
+ } else {
189
+ cart.set([...cartItems, { ...product, count: 1 }]);
190
+ }
191
+ };
192
+
193
+ return (
194
+ <div>
195
+ <h2>🛍️ Products</h2>
196
+ <ul>
197
+ {productItems.map((productItem: ProductType, index: number) => (
198
+ <li key={index}>
199
+ {productItem.name} - ${productItem.price}{" "}
200
+ <button onClick={() => addToCart(productItem)}>Add to Cart</button>
201
+ </li>
202
+ ))}
203
+ </ul>
204
+ </div>
205
+ );
206
+ };
207
+
95
208
  ```
96
209
 
97
210
  ## Middlewares
@@ -111,23 +224,42 @@ function useStateGlobal<T>(
111
224
 
112
225
  You can log your store for every action.
113
226
 
114
- ```tsx
115
- import { useStateGlobal } from "state-jet";
227
+ ```ts
228
+ // file: src/store/middleware.ts
116
229
 
117
- const loggerMiddleware = (key: string, prev: number, next: number) => {
230
+ export const loggerMiddleware = (key: string, prev: number, next: number) => {
118
231
  console.log(`[state-jet] ${key}: ${prev} → ${next}`);
119
232
  };
120
233
 
121
- const counter = useStateGlobal("counter", 0, { middleware: [loggerMiddleware] });
234
+ ```
235
+
236
+ Create global state with loggerMiddleware
237
+
238
+ ```ts
239
+ // file: src/store/index.ts
240
+
241
+ import { useStateGlobal } from "state-jet";
242
+ import { loggerMiddleware } from "./middleware";
243
+
244
+ export const counterState = useStateGlobal("counter", 0, { middleware: [loggerMiddleware] });
245
+
246
+ ```
247
+
248
+ Binding Global State to a Component
249
+
250
+ ```tsx
251
+ // file: src/components/Counter.tsx
252
+
253
+ import { counterState } from "../store";
122
254
 
123
255
  export default function Counter() {
124
- const count = counter.useState() as number;
256
+ const count = counterState.useState() as number;
125
257
 
126
258
  return (
127
259
  <div>
128
260
  <h1>Counter: {count}</h1>
129
- <button onClick={() => counter.set(count - 1)}>Decrement</button>
130
- <button onClick={() => counter.set(count + 1)}>Increment</button>
261
+ <button onClick={() => counterState.set(count - 1)}>Decrement</button>
262
+ <button onClick={() => counterState.set(count + 1)}>Increment</button>
131
263
  </div>
132
264
  );
133
265
  }
@@ -137,8 +269,8 @@ export default function Counter() {
137
269
 
138
270
  Can't live without reducer?. No worries. StateJet supports reducer middleware
139
271
 
140
- ```tsx
141
- import { useStateGlobal } from "state-jet";
272
+ ```ts
273
+ // file: src/store/middleware.ts
142
274
 
143
275
  type Action<T> = { type: string; payload?: T };
144
276
  type Middleware<T> = (
@@ -148,7 +280,7 @@ type Middleware<T> = (
148
280
  set?: (value: T) => void,
149
281
  ) => T | void | Promise<void>;
150
282
 
151
- const reducerMiddleware: Middleware<number> = (key, prev, action: Action<any>) => {
283
+ export const reducerMiddleware: Middleware<number> = (key, prev, action: Action<any>) => {
152
284
  switch (action.type) {
153
285
  case "INCREMENT":
154
286
  return prev + 1;
@@ -160,31 +292,83 @@ const reducerMiddleware: Middleware<number> = (key, prev, action: Action<any>) =
160
292
  return prev;
161
293
  }
162
294
  }
295
+ ```
296
+
297
+ Create global state with reducerMiddleware
298
+
299
+ ```ts
300
+ // file: src/store/index.ts
301
+
302
+ import { useStateGlobal } from "state-jet";
303
+ import { reducerMiddleware } from "./middleware";
304
+
305
+ export const counterState = useStateGlobal("counter", 0, { middleware: [reducerMiddleware] });
306
+
307
+ ```
308
+
309
+ Binding Global State to a Component
163
310
 
164
- const counter = useStateGlobal("counter", 0, { middleware: [reducerMiddleware] });
311
+ ```tsx
312
+ // file: src/components/Counter.tsx
313
+
314
+ import { counterState } from "../store";
165
315
 
166
316
  export default function Counter() {
167
- const count = counter.useState() as number;
317
+ const count = counterState.useState() as number;
168
318
 
169
319
  return (
170
320
  <div>
171
321
  <h1>Counter: {count}</h1>
172
- <button onClick={() => counter.set({ type: "DECREMENT" })}>Decrement</button>
173
- <button onClick={() => counter.set({ type: "INCREMENT" })}>Increment</button>
174
- <button onClick={() => counter.set({ type: "RESET" })}>Reset</button>
322
+ <button onClick={() => counterState.set({ type: "DECREMENT" })}>Decrement</button>
323
+ <button onClick={() => counterState.set({ type: "INCREMENT" })}>Increment</button>
324
+ <button onClick={() => counterState.set({ type: "RESET" })}>Reset</button>
175
325
  </div>
176
326
  );
177
327
  }
178
328
  ```
179
329
 
330
+ ### Debounce Middleware
331
+
332
+ You can delay the update of global state
333
+
334
+ ```ts
335
+ // file: src/store/middleware.ts
336
+
337
+ let timer: ReturnType<typeof setTimeout>;
338
+
339
+ // Debounce middleware with delay
340
+ export const debounceMiddleware = (delay: number) => {
341
+ return (key: string, prev: number, next: any, set?: (value: any) => void) => {
342
+ clearTimeout(timer);
343
+ if (set) {
344
+ timer = setTimeout(() => {
345
+ console.log(`[state-jet] Debounced: ${key} → ${next}`);
346
+ set(next); // Apply the debounced update
347
+ }, delay);
348
+ }
349
+ };
350
+ };
351
+ ```
352
+
353
+ Create global state with debounceMiddleware
354
+
355
+ ```ts
356
+ // file: src/store/index.ts
357
+
358
+ import { useStateGlobal } from "state-jet";
359
+ import { debounceMiddleware } from "./middleware";
360
+
361
+ export const counterState = useStateGlobal("counter", 0, { middleware: [debounceMiddleware(500)] });
362
+ ```
363
+
180
364
  ### Optimistic Middleware
181
365
 
182
366
  You can optimistically update global state with rollback support
183
367
 
184
- ```tsx
185
- import { useStateGlobal } from "state-jet";
368
+ ```ts
369
+ // file: src/store/middleware.ts
186
370
 
187
- const optimisticMiddleware = (apiUrl: string) => {
371
+ export const optimisticMiddleware = (apiUrl: string) => {
188
372
  return async (key: string, prev: number, next: number, set: any) => {
189
373
  set(next); // Optimistically update state
190
374
 
@@ -200,26 +384,55 @@ const optimisticMiddleware = (apiUrl: string) => {
200
384
  }
201
385
  };
202
386
  };
203
- const profile = useStateGlobal("profile", { name: "John" }, {
387
+ ```
388
+
389
+ Create global state with optimisticMiddleware
390
+
391
+ ```ts
392
+ // file: src/store/index.ts
393
+
394
+ import { useStateGlobal } from "state-jet";
395
+ import { optimisticMiddleware } from "./middleware";
396
+
397
+ export const profileState = useStateGlobal("profile", { name: "John" }, {
204
398
  middleware: [optimisticMiddleware("/update-profile")],
205
399
  });
206
400
  ```
207
401
 
208
402
  ### Custom Middleware
209
403
 
210
- You can create your own custom middleware in state-jet
404
+ You can also create your own custom middleware in state-jet
211
405
 
212
- ```tsx
213
- import { useStateGlobal } from "state-jet";
406
+ ```ts
407
+ // file: src/store/middleware.ts
214
408
 
215
- const validateAgeMiddleware = (key: string, prev: number, next: number) => {
409
+ export const validateAgeMiddleware = (key: string, prev: number, next: number) => {
216
410
  if (next < 0) {
217
411
  console.warn("Age cannot be negative!");
218
412
  return prev;
219
413
  }
220
414
  return next;
221
415
  };
222
- const ageState = useStateGlobal("age", 0, { middleware: [validateAgeMiddleware] });
416
+ ```
417
+
418
+ Create global state with validateAgeMiddleware
419
+
420
+ ```ts
421
+ // file: src/store/index.ts
422
+
423
+ import { useStateGlobal } from "state-jet";
424
+ import { validateAgeMiddleware } from "./middleware";
425
+
426
+ export const ageState = useStateGlobal("age", 0, { middleware: [validateAgeMiddleware] });
427
+
428
+ ```
429
+
430
+ Binding Global State to a Component
431
+
432
+ ```tsx
433
+ // file: src/components/Profile.tsx
434
+
435
+ import { ageState } from "../store";
223
436
 
224
437
  export default function Profile() {
225
438
  const age = ageState.useState() as number;
@@ -229,7 +442,7 @@ export default function Profile() {
229
442
  <h1>Age: {age}</h1>
230
443
  <button
231
444
  onClick={() => {
232
- counter.set(-5) // Age will be 0 eventhough it updated with negative value due to middleware logic
445
+ ageState.set(-5) // Age will be 0 eventhough it updated with negative value due to middleware logic
233
446
  }}>
234
447
  Set negative
235
448
  </button>
@@ -256,19 +469,18 @@ const todoState = useStateGlobal<Todo[]>("todos", []);
256
469
 
257
470
  ## Why state-jet Is More Advanced Than Zustand
258
471
 
259
- - **No Proxies Needed**
260
- Zustand uses proxies for state updates, but state-jet uses signals, making it even faster.
261
- - **Derived State Is Automatic**
262
- No need for selectors; state updates only trigger where necessary.
263
- - **Optimistic Updates & Rollback**
264
- → Unlike Zustand, state-jet has built-in support for instant UI updates and auto-revert on failures.
265
- - **Multi-Tab Sync**
266
- → global state persists across browser tabs and devices.
267
- - **CRDT Support**
268
- → Automatic conflict resolution for real-time apps, something even Zustand lacks.
472
+ - **No Proxies Needed**: Zustand uses proxies for state updates, but state-jet uses signals, making it even faster.
473
+ - **Derived State Is Automatic**: No need for selectors; state updates only trigger where necessary.
474
+ - **Optimistic Updates & Rollback**: Unlike Zustand, state-jet has built-in support for instant UI updates and auto-revert on failures.
475
+ - **Multi-Tab Sync**: Global state persists across browser tabs and devices.
476
+ - **CRDT Support**: Automatic conflict resolution for real-time apps, something even Zustand lacks.
269
477
 
478
+ ## FAQ
479
+ - If you want to manage your global state like `useState` as usual.
480
+ - If you want to manage your global state without involving in setting up Provider Component, Dispatcher, Reducer, etc.
481
+ - If you want to see `Redux` or `Context API` alternative.
270
482
 
271
- ### Conclusion
483
+ ## Conclusion
272
484
 
273
485
  If you need the simplest, fastest, and most advanced state management solution for React, state-jet beats Redux, Recoil, MobX, Jotai, and even Zustand in performance, reactivity, and developer experience. 🚀
274
486
 
@@ -295,6 +507,12 @@ Development of State-jet happens in the open on GitHub, and we are grateful to t
295
507
 
296
508
  - [Contributing Guide](./CONTRIBUTING.md)
297
509
 
298
- ### License
510
+ ## Publishing
511
+ - Before pushing your changes to Github, make sure that `version` in `package.json` is changed to newest version. Then run `npm install` for synchronize it to `package-lock.json` and `pnpm install` for synchronize it to `pnpm-lock.yaml`
512
+
513
+ ## Feedbacks and Issues
514
+ Feel free to open issues if you found any feedback or issues on `state-jet`. And feel free if you want to contribute too! 😄
515
+
516
+ ## License
299
517
 
300
518
  State-jet is [MIT licensed](./LICENSE).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "state-jet",
3
- "version": "2.0.16",
3
+ "version": "2.0.17",
4
4
  "description": "Ultra-lightweight global state management for React",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -31,8 +31,29 @@
31
31
  "global-state-management",
32
32
  "signals",
33
33
  "state-jet",
34
+ "statejet",
35
+ "state-jet-react",
34
36
  "jet",
35
- "store"
37
+ "react-jet",
38
+ "jetstate",
39
+ "jet-state",
40
+ "react-jetstate",
41
+ "react-hooks",
42
+ "store",
43
+ "hooks",
44
+ "javascript",
45
+ "typescript",
46
+ "global",
47
+ "react-state-management",
48
+ "state-manager",
49
+ "global-state-hooks",
50
+ "state-hooks",
51
+ "use-store",
52
+ "client-state",
53
+ "react-utility",
54
+ "hooks-utility",
55
+ "redux-alternative",
56
+ "context-alternative"
36
57
  ],
37
58
  "author": "venkateshsundaram",
38
59
  "license": "MIT",