state-jet 2.0.16 → 2.0.18

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 +279 -55
  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 Store to a Component](#binding-store-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.
@@ -13,9 +47,9 @@ For more details, see [here](https://statejet.netlify.app).
13
47
 
14
48
  Documentation: https://statejet.netlify.app/docs
15
49
 
16
- Tutorials: https://statejet.netlify.app/docs/category/tutorial
50
+ Tutorials: https://statejet.netlify.app/docs/tutorial/intro/
17
51
 
18
- API Reference: https://statejet.netlify.app/docs/category/api-reference
52
+ API Reference: https://statejet.netlify.app/docs/api-reference/global-state/
19
53
 
20
54
  Wiki: https://deepwiki.com/venkateshsundaram/state-jet
21
55
 
@@ -43,18 +77,35 @@ Or if you're using `cdn`:
43
77
 
44
78
  ## GlobalState
45
79
 
46
- The `useStateGlobal` hook is the simplest entry point to State-Jet. It allows you to create stateful values that can be accessed and updated from any component in your application, regardless of their location in the component tree.
80
+ The `useStateGlobal` hook is the simplest entry point to State-Jet—-ideal for simple applications with minimal state management needs. It allows you to create stateful values that can be accessed and updated from any component in your application, regardless of their location in the component tree.
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
 
@@ -62,36 +113,104 @@ function Counter() {
62
113
 
63
114
  Slices in state-jet represent logical groupings of state that help organize application data into manageable pieces. Unlike the global state approach which uses a single namespace, slices allow for partitioning state into named segments, making state management more modular and maintainable.
64
115
 
65
- Each slice can contain multiple state values, each identified by a unique key within that slice.
66
-
67
116
  ### Create Slice
68
117
 
69
- ```tsx
118
+ ```ts
119
+ // file: src/store/slices.ts
120
+
70
121
  import { useSlice } from "state-jet";
71
122
 
72
123
  const productSlice = useSlice("products");
73
124
  const cartSlice = useSlice("cart");
74
125
 
75
- export const useProductSlice = () => productSlice("list", []);
76
- export const useCartSlice = () => cartSlice("list", []);
126
+ export const useProductSlice = () => productSlice("productState", {});
127
+ export const useCartSlice = () => cartSlice("cartState", {});
77
128
  ```
78
129
 
79
130
  ## Store
80
131
 
81
- The `useStore` hook serves as a mechanism to group related slices of state into a cohesive store, enabling modular and organized state management in React applications. It creates a persistent reference to a collection of slice instances that can be accessed throughout an application component tree.
132
+ The `useStore` hook serves as a mechanism to group related slices of state into a cohesive store, enabling modular and organized state management in React applications which are better suited for larger applications with more complex and structured state requirements.
82
133
 
83
134
  ### Create Store
84
135
 
85
- ```tsx
136
+ ```ts
137
+ // file: src/store/index.ts
138
+
86
139
  import { useStore } from "state-jet";
87
140
  import { useProductSlice, useCartSlice } from "./slices";
88
141
 
142
+ /**
143
+ * Ecommerce store with product and cart slices
144
+ */
89
145
  const initializer: any = () => ({
90
146
  products: useProductSlice(),
91
147
  cart: useCartSlice(),
92
148
  });
93
149
 
94
- export const store = () => useStore(initializer);
150
+ export const useEcommerceStore = () => useStore(initializer);
151
+ ```
152
+
153
+ ### Binding Store to a Component
154
+
155
+ ```tsx
156
+ // file: src/components/ProductList.tsx
157
+
158
+ import { useEcommerceStore } from "../store";
159
+
160
+ type ProductType = {
161
+ name: string,
162
+ price: number
163
+ }
164
+
165
+ type CartType = {
166
+ name: string,
167
+ price: number,
168
+ count: number
169
+ }
170
+
171
+ export const ProductList = () => {
172
+ const store = useEcommerceStore();
173
+ const products: any = store.products;
174
+ const cart: any = store.cart;
175
+ const productSliceData: any = products.useState();
176
+ const cartSliceData: any = cart.useState();
177
+ const productItems: Array<ProductType> = productSliceData?.items || [];
178
+ const cartItems: Array<CartType> = cartSliceData?.items || [];
179
+
180
+ const addToCart = (product: ProductType) => {
181
+ if (cartItems.some((cartItem: CartType) => cartItem.name === product.name)) {
182
+ cart.set((cartVal: any)=> ({
183
+ ...cartVal,
184
+ items: cartItems.map((cartItem: CartType) => {
185
+ if (cartItem.name === product.name) {
186
+ return { ...cartItem, count: (cartItem.count || 0) + 1 };
187
+ }
188
+ return cartItem;
189
+ })
190
+ }));
191
+ } else {
192
+ cart.set((cartVal: any)=> ({
193
+ ...cartVal,
194
+ items: [...cartItems, { ...product, count: 1 }]
195
+ }));
196
+ }
197
+ };
198
+
199
+ return (
200
+ <div>
201
+ <h2>🛍️ Products</h2>
202
+ <ul>
203
+ {productItems && productItems.map((productItem: ProductType, index: number) => (
204
+ <li key={index}>
205
+ {productItem.name} - ${productItem.price}{" "}
206
+ <button onClick={() => addToCart(productItem)}>Add to Cart</button>
207
+ </li>
208
+ ))}
209
+ </ul>
210
+ </div>
211
+ );
212
+ };
213
+
95
214
  ```
96
215
 
97
216
  ## Middlewares
@@ -111,23 +230,42 @@ function useStateGlobal<T>(
111
230
 
112
231
  You can log your store for every action.
113
232
 
114
- ```tsx
115
- import { useStateGlobal } from "state-jet";
233
+ ```ts
234
+ // file: src/store/middleware.ts
116
235
 
117
- const loggerMiddleware = (key: string, prev: number, next: number) => {
236
+ export const loggerMiddleware = (key: string, prev: number, next: number) => {
118
237
  console.log(`[state-jet] ${key}: ${prev} → ${next}`);
119
238
  };
120
239
 
121
- const counter = useStateGlobal("counter", 0, { middleware: [loggerMiddleware] });
240
+ ```
241
+
242
+ Create global state with loggerMiddleware
243
+
244
+ ```ts
245
+ // file: src/store/index.ts
246
+
247
+ import { useStateGlobal } from "state-jet";
248
+ import { loggerMiddleware } from "./middleware";
249
+
250
+ export const counterState = useStateGlobal("counter", 0, { middleware: [loggerMiddleware] });
251
+
252
+ ```
253
+
254
+ Binding Global State to a Component
255
+
256
+ ```tsx
257
+ // file: src/components/Counter.tsx
258
+
259
+ import { counterState } from "../store";
122
260
 
123
261
  export default function Counter() {
124
- const count = counter.useState() as number;
262
+ const count = counterState.useState() as number;
125
263
 
126
264
  return (
127
265
  <div>
128
266
  <h1>Counter: {count}</h1>
129
- <button onClick={() => counter.set(count - 1)}>Decrement</button>
130
- <button onClick={() => counter.set(count + 1)}>Increment</button>
267
+ <button onClick={() => counterState.set(count - 1)}>Decrement</button>
268
+ <button onClick={() => counterState.set(count + 1)}>Increment</button>
131
269
  </div>
132
270
  );
133
271
  }
@@ -135,10 +273,10 @@ export default function Counter() {
135
273
 
136
274
  ### Reducer Middleware
137
275
 
138
- Can't live without reducer?. No worries. StateJet supports reducer middleware
276
+ Can't live without reducer? No worries, StateJet supports reducer middleware.
139
277
 
140
- ```tsx
141
- import { useStateGlobal } from "state-jet";
278
+ ```ts
279
+ // file: src/store/middleware.ts
142
280
 
143
281
  type Action<T> = { type: string; payload?: T };
144
282
  type Middleware<T> = (
@@ -148,7 +286,7 @@ type Middleware<T> = (
148
286
  set?: (value: T) => void,
149
287
  ) => T | void | Promise<void>;
150
288
 
151
- const reducerMiddleware: Middleware<number> = (key, prev, action: Action<any>) => {
289
+ export const reducerMiddleware: Middleware<number> = (key, prev, action: Action<any>) => {
152
290
  switch (action.type) {
153
291
  case "INCREMENT":
154
292
  return prev + 1;
@@ -160,31 +298,83 @@ const reducerMiddleware: Middleware<number> = (key, prev, action: Action<any>) =
160
298
  return prev;
161
299
  }
162
300
  }
301
+ ```
302
+
303
+ Create global state with reducerMiddleware
163
304
 
164
- const counter = useStateGlobal("counter", 0, { middleware: [reducerMiddleware] });
305
+ ```ts
306
+ // file: src/store/index.ts
307
+
308
+ import { useStateGlobal } from "state-jet";
309
+ import { reducerMiddleware } from "./middleware";
310
+
311
+ export const counterState = useStateGlobal("counter", 0, { middleware: [reducerMiddleware] });
312
+
313
+ ```
314
+
315
+ Binding Global State to a Component
316
+
317
+ ```tsx
318
+ // file: src/components/Counter.tsx
319
+
320
+ import { counterState } from "../store";
165
321
 
166
322
  export default function Counter() {
167
- const count = counter.useState() as number;
323
+ const count = counterState.useState() as number;
168
324
 
169
325
  return (
170
326
  <div>
171
327
  <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>
328
+ <button onClick={() => counterState.set({ type: "DECREMENT" })}>Decrement</button>
329
+ <button onClick={() => counterState.set({ type: "INCREMENT" })}>Increment</button>
330
+ <button onClick={() => counterState.set({ type: "RESET" })}>Reset</button>
175
331
  </div>
176
332
  );
177
333
  }
178
334
  ```
179
335
 
180
- ### Optimistic Middleware
336
+ ### Debounce Middleware
181
337
 
182
- You can optimistically update global state with rollback support
338
+ You can delay the update of global state.
339
+
340
+ ```ts
341
+ // file: src/store/middleware.ts
342
+
343
+ let timer: ReturnType<typeof setTimeout>;
344
+
345
+ // Debounce middleware with delay
346
+ export const debounceMiddleware = (delay: number) => {
347
+ return (key: string, prev: number, next: any, set?: (value: any) => void) => {
348
+ clearTimeout(timer);
349
+ if (set) {
350
+ timer = setTimeout(() => {
351
+ console.log(`[state-jet] Debounced: ${key} → ${next}`);
352
+ set(next); // Apply the debounced update
353
+ }, delay);
354
+ }
355
+ };
356
+ };
357
+ ```
358
+
359
+ Create global state with debounceMiddleware
360
+
361
+ ```ts
362
+ // file: src/store/index.ts
183
363
 
184
- ```tsx
185
364
  import { useStateGlobal } from "state-jet";
365
+ import { debounceMiddleware } from "./middleware";
366
+
367
+ export const counterState = useStateGlobal("counter", 0, { middleware: [debounceMiddleware(500)] });
368
+ ```
186
369
 
187
- const optimisticMiddleware = (apiUrl: string) => {
370
+ ### Optimistic Middleware
371
+
372
+ You can optimistically update global state with rollback support.
373
+
374
+ ```ts
375
+ // file: src/store/middleware.ts
376
+
377
+ export const optimisticMiddleware = (apiUrl: string) => {
188
378
  return async (key: string, prev: number, next: number, set: any) => {
189
379
  set(next); // Optimistically update state
190
380
 
@@ -200,26 +390,55 @@ const optimisticMiddleware = (apiUrl: string) => {
200
390
  }
201
391
  };
202
392
  };
203
- const profile = useStateGlobal("profile", { name: "John" }, {
393
+ ```
394
+
395
+ Create global state with optimisticMiddleware
396
+
397
+ ```ts
398
+ // file: src/store/index.ts
399
+
400
+ import { useStateGlobal } from "state-jet";
401
+ import { optimisticMiddleware } from "./middleware";
402
+
403
+ export const profileState = useStateGlobal("profile", { name: "John" }, {
204
404
  middleware: [optimisticMiddleware("/update-profile")],
205
405
  });
206
406
  ```
207
407
 
208
408
  ### Custom Middleware
209
409
 
210
- You can create your own custom middleware in state-jet
410
+ You can also create your own custom middleware in state-jet.
211
411
 
212
- ```tsx
213
- import { useStateGlobal } from "state-jet";
412
+ ```ts
413
+ // file: src/store/middleware.ts
214
414
 
215
- const validateAgeMiddleware = (key: string, prev: number, next: number) => {
415
+ export const validateAgeMiddleware = (key: string, prev: number, next: number) => {
216
416
  if (next < 0) {
217
417
  console.warn("Age cannot be negative!");
218
418
  return prev;
219
419
  }
220
420
  return next;
221
421
  };
222
- const ageState = useStateGlobal("age", 0, { middleware: [validateAgeMiddleware] });
422
+ ```
423
+
424
+ Create global state with validateAgeMiddleware
425
+
426
+ ```ts
427
+ // file: src/store/index.ts
428
+
429
+ import { useStateGlobal } from "state-jet";
430
+ import { validateAgeMiddleware } from "./middleware";
431
+
432
+ export const ageState = useStateGlobal("age", 0, { middleware: [validateAgeMiddleware] });
433
+
434
+ ```
435
+
436
+ Binding Global State to a Component
437
+
438
+ ```tsx
439
+ // file: src/components/Profile.tsx
440
+
441
+ import { ageState } from "../store";
223
442
 
224
443
  export default function Profile() {
225
444
  const age = ageState.useState() as number;
@@ -229,7 +448,7 @@ export default function Profile() {
229
448
  <h1>Age: {age}</h1>
230
449
  <button
231
450
  onClick={() => {
232
- counter.set(-5) // Age will be 0 eventhough it updated with negative value due to middleware logic
451
+ ageState.set(-5) // Age will be 0 eventhough it updated with negative value due to middleware logic
233
452
  }}>
234
453
  Set negative
235
454
  </button>
@@ -256,19 +475,18 @@ const todoState = useStateGlobal<Todo[]>("todos", []);
256
475
 
257
476
  ## Why state-jet Is More Advanced Than Zustand
258
477
 
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.
478
+ - **No Proxies Needed**: Zustand uses proxies for state updates, but state-jet uses signals, making it even faster.
479
+ - **Derived State Is Automatic**: No need for selectors; state updates only trigger where necessary.
480
+ - **Optimistic Updates & Rollback**: Unlike Zustand, state-jet has built-in support for instant UI updates and auto-revert on failures.
481
+ - **Multi-Tab Sync**: Global state persists across browser tabs and devices.
482
+ - **CRDT Support**: Automatic conflict resolution for real-time apps, something even Zustand lacks.
269
483
 
484
+ ## FAQ
485
+ - If you want to manage your global state like `useState` as usual.
486
+ - If you want to manage your global state without involving in setting up Provider Component, Dispatcher, Reducer, etc.
487
+ - If you want to see `Redux` or `Context API` alternative.
270
488
 
271
- ### Conclusion
489
+ ## Conclusion
272
490
 
273
491
  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
492
 
@@ -295,6 +513,12 @@ Development of State-jet happens in the open on GitHub, and we are grateful to t
295
513
 
296
514
  - [Contributing Guide](./CONTRIBUTING.md)
297
515
 
298
- ### License
516
+ ## Publishing
517
+ 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`
518
+
519
+ ## Feedbacks and Issues
520
+ Feel free to open issues if you found any feedback or issues on `state-jet`. And feel free if you want to contribute too! 😄
521
+
522
+ ## License
299
523
 
300
524
  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.18",
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",