state-jet 2.0.6 → 2.0.8
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 +171 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
A zero-boilerplate, ultra-fast global state management library for React.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
For more Information, see [here](https://statejet.netlify.app).
|
|
3
|
+
For more details, see [here](https://statejet.netlify.app).
|
|
6
4
|
|
|
7
5
|
## 🚀 Why state-jet?
|
|
8
6
|
|
|
@@ -43,7 +41,7 @@ Or if you're using `cdn`:
|
|
|
43
41
|
|
|
44
42
|
## Basic Example Usage
|
|
45
43
|
|
|
46
|
-
```
|
|
44
|
+
```tsx
|
|
47
45
|
import { useStateGlobal } from "state-jet";
|
|
48
46
|
|
|
49
47
|
const counter = useStateGlobal("counter", 0);
|
|
@@ -53,7 +51,7 @@ function Counter() {
|
|
|
53
51
|
return <button onClick={() => counter.set(count + 1)}>Count: {count}</button>;
|
|
54
52
|
}
|
|
55
53
|
```
|
|
56
|
-
##
|
|
54
|
+
## Why state-jet Is More Advanced Than Zustand
|
|
57
55
|
|
|
58
56
|
- **No Proxies Needed** → Zustand uses proxies for state updates, but state-jet uses signals, making it even faster.
|
|
59
57
|
- **Derived State Is Automatic** → No need for selectors; state updates only trigger where necessary.
|
|
@@ -61,26 +59,27 @@ function Counter() {
|
|
|
61
59
|
- **Multi-Tab Sync** → global state persists across browser tabs and devices.
|
|
62
60
|
- **CRDT Support** → Automatic conflict resolution for real-time apps, something even Zustand lacks.
|
|
63
61
|
|
|
64
|
-
### ✅Conclusion
|
|
62
|
+
### ✅ Conclusion
|
|
65
63
|
|
|
66
64
|
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. 🚀
|
|
67
65
|
|
|
68
66
|
## Create Slice
|
|
69
67
|
|
|
70
|
-
```
|
|
68
|
+
```tsx
|
|
71
69
|
import { useSlice } from "state-jet";
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
useSlice("cart")("items", []);
|
|
71
|
+
const productSlice = useSlice("products");
|
|
72
|
+
const cartSlice = useSlice("cart");
|
|
73
|
+
const userSlice = useSlice("user");
|
|
77
74
|
|
|
78
|
-
export const
|
|
75
|
+
export const useProductSlice = () => productSlice("list", []);
|
|
76
|
+
export const useCartSlice = () => cartSlice("items", []);
|
|
77
|
+
export const useUserSlice = () => userSlice("info", null);
|
|
79
78
|
```
|
|
80
79
|
|
|
81
80
|
## Create Store
|
|
82
81
|
|
|
83
|
-
```
|
|
82
|
+
```tsx
|
|
84
83
|
import { useStore } from "state-jet";
|
|
85
84
|
import { useProductSlice, useCartSlice, useUserSlice } from "./slices";
|
|
86
85
|
|
|
@@ -93,6 +92,164 @@ const initializer: any = () => ({
|
|
|
93
92
|
export const useEcommerceStore = () => useStore(initializer);
|
|
94
93
|
```
|
|
95
94
|
|
|
95
|
+
## Middlewares
|
|
96
|
+
|
|
97
|
+
Unlike other libraries, you do not need to rely on any external dependencies. A `middleware` property from `options` helps to add middleware for state-jet.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
function useStateGlobal<T>(
|
|
101
|
+
...
|
|
102
|
+
options?: { middleware?: Middleware<T>[] }
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Logger Middleware
|
|
107
|
+
|
|
108
|
+
You can log your store for every action.
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import { useStateGlobal } from "state-jet";
|
|
112
|
+
|
|
113
|
+
const loggerMiddleware = (key: string, prev: number, next: number) => {
|
|
114
|
+
console.log(`[state-jet] ${key}: ${prev} → ${next}`);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const counter = useStateGlobal("counter", 0, { middleware: [loggerMiddleware] });
|
|
118
|
+
|
|
119
|
+
export default function Counter() {
|
|
120
|
+
const count = counter.useState() as number;
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<div>
|
|
124
|
+
<h1>Counter: {count}</h1>
|
|
125
|
+
<button onClick={() => counter.set(count - 1)}>Decrement</button>
|
|
126
|
+
<button onClick={() => counter.set(count + 1)}>Increment</button>
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Reducer Middleware
|
|
133
|
+
|
|
134
|
+
Can't live without reducer?. No worries. StateJet supports reducer middleware
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import { useStateGlobal } from "state-jet";
|
|
138
|
+
|
|
139
|
+
type Action<T> = { type: string; payload?: T };
|
|
140
|
+
type Middleware<T> = (
|
|
141
|
+
key: string,
|
|
142
|
+
prev: T,
|
|
143
|
+
next: T | Action<T> | any,
|
|
144
|
+
set?: (value: T) => void,
|
|
145
|
+
) => T | void | Promise<void>;
|
|
146
|
+
|
|
147
|
+
const reducerMiddleware: Middleware<number> = (key, prev, action: Action<any>) => {
|
|
148
|
+
switch (action.type) {
|
|
149
|
+
case "INCREMENT":
|
|
150
|
+
return prev + 1;
|
|
151
|
+
case "DECREMENT":
|
|
152
|
+
return prev - 1;
|
|
153
|
+
case "RESET":
|
|
154
|
+
return 0;
|
|
155
|
+
default:
|
|
156
|
+
return prev;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const counter = useStateGlobal("counter", 0, { middleware: [reducerMiddleware] });
|
|
161
|
+
|
|
162
|
+
export default function Counter() {
|
|
163
|
+
const count = counter.useState() as number;
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<div>
|
|
167
|
+
<h1>Counter: {count}</h1>
|
|
168
|
+
<button onClick={() => counter.set({ type: "DECREMENT" })}>Decrement</button>
|
|
169
|
+
<button onClick={() => counter.set({ type: "INCREMENT" })}>Increment</button>
|
|
170
|
+
<button onClick={() => counter.set({ type: "RESET" })}>Reset</button>
|
|
171
|
+
</div>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Optimistic Middleware
|
|
177
|
+
|
|
178
|
+
You can optimistically update global state with rollback support
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
import { useStateGlobal } from "state-jet";
|
|
182
|
+
|
|
183
|
+
const optimisticMiddleware = (apiUrl: string) => {
|
|
184
|
+
return async (key: string, prev: number, next: number, set: any) => {
|
|
185
|
+
set(next); // Optimistically update state
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
await fetch(apiUrl, {
|
|
189
|
+
method: "POST",
|
|
190
|
+
body: JSON.stringify({ key, value: next }),
|
|
191
|
+
headers: { "Content-Type": "application/json" },
|
|
192
|
+
});
|
|
193
|
+
} catch (error) {
|
|
194
|
+
console.warn(`[state-jet] Rollback: Failed to sync ${key}`);
|
|
195
|
+
set(prev); // Rollback state on failure
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
};
|
|
199
|
+
const profile = useStateGlobal("profile", { name: "John" }, {
|
|
200
|
+
middleware: [optimisticMiddleware("/update-profile")],
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Custom Middleware
|
|
205
|
+
|
|
206
|
+
You can create your own custom middleware in state-jet
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
import { useStateGlobal } from "state-jet";
|
|
210
|
+
|
|
211
|
+
const validateAgeMiddleware = (key: string, prev: number, next: number) => {
|
|
212
|
+
if (key === "age" && next < 0) {
|
|
213
|
+
console.warn("Age cannot be negative!");
|
|
214
|
+
return prev;
|
|
215
|
+
}
|
|
216
|
+
return next;
|
|
217
|
+
};
|
|
218
|
+
const ageState = useStateGlobal("age", 0, { middleware: [validateAgeMiddleware] });
|
|
219
|
+
|
|
220
|
+
export default function Profile() {
|
|
221
|
+
const age = ageState.useState() as number;
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<div>
|
|
225
|
+
<h1>Age: {age}</h1>
|
|
226
|
+
<button
|
|
227
|
+
onClick={() => {
|
|
228
|
+
counter.set(-5) //Age will be 0 eventhough it updated with negative value due to middleware logic
|
|
229
|
+
}}>
|
|
230
|
+
Set negative
|
|
231
|
+
</button>
|
|
232
|
+
</div>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
A more complete middleware usage is [here](https://statejet.netlify.app/docs/api-reference/middlewares/).
|
|
238
|
+
|
|
239
|
+
## Typescript Usage
|
|
240
|
+
|
|
241
|
+
Here is the example for creating global state with typescript definition.
|
|
242
|
+
|
|
243
|
+
```tsx
|
|
244
|
+
interface Todo = {
|
|
245
|
+
id: number;
|
|
246
|
+
text: string;
|
|
247
|
+
completed: boolean
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const todoState = useStateGlobal<Todo[]>("todos", []);
|
|
251
|
+
```
|
|
252
|
+
|
|
96
253
|
## ⚡ Comparison Table
|
|
97
254
|
| Feature | Redux | Recoil | MobX | Jotai | Zustand | state-jet |
|
|
98
255
|
|--------------------------|--------|--------|-------|--------|------------------------|----------------------|
|