zustic 1.0.1 โ 1.0.3
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 +322 -282
- package/dist/chunk-SISWF3T4.mjs +1 -0
- package/dist/index.js +1 -73
- package/dist/index.mjs +1 -51
- package/dist/query/index.d.mts +116 -0
- package/dist/query/index.d.ts +116 -0
- package/dist/query/index.js +1 -0
- package/dist/query/index.mjs +1 -0
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -1,42 +1,91 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# ๐ฏ Zustic
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
[](LICENSE)
|
|
7
|
-
[](https://bundlephobia.com/package/zustic)
|
|
5
|
+
### Lightweight State Management for Modern React Applications
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
[](https://npm.im/zustic)
|
|
8
|
+
[](https://npm.im/zustic)
|
|
9
|
+
[](https://bundlephobia.com/result?p=zustic)
|
|
10
|
+
[](LICENSE)
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
โก **Simple API** - Intuitive and easy to learn state management
|
|
13
|
-
๐ฃ **React Hooks** - Use hooks to access state in your components
|
|
14
|
-
๐ฑ **Multi-Platform** - Works with React, React Native, and Next.js
|
|
15
|
-
๐ **Reactive Updates** - Automatic re-renders on state changes
|
|
16
|
-
๐พ **TypeScript Support** - Full TypeScript support with type safety
|
|
17
|
-
๐ **Production Ready** - Optimized for performance and reliability
|
|
12
|
+
A **fast, minimal state management solution** for React ecosystems. Works seamlessly with React, Next.js, and React Native with predictable state updates and a tiny footprint.
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
[๐ Documentation](https://zustic.github.io/) ยท [๐ Report Bug](https://github.com/DeveloperRejaul/zustic/issues) ยท [๐ก Request Feature](https://github.com/DeveloperRejaul/zustic/issues)
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
npm install zustic
|
|
23
|
-
```
|
|
16
|
+
</div>
|
|
24
17
|
|
|
25
|
-
|
|
18
|
+
---
|
|
26
19
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
## โจ Key Features
|
|
21
|
+
|
|
22
|
+
### Core Features
|
|
23
|
+
- **๐ชถ Ultra-Lightweight** โ Only ~500B (gzipped) with zero dependencies
|
|
24
|
+
- **โก Simple API** โ One function (`create`) to manage all your state
|
|
25
|
+
- **๐ฃ React Hooks** โ Native React hooks integration with automatic subscriptions
|
|
26
|
+
- **๐ฑ Multi-Platform** โ React, React Native, Next.js, and modern frameworks
|
|
27
|
+
- **๐ Reactive Updates** โ Automatic re-renders with optimized batching
|
|
28
|
+
- **๐พ TypeScript First** โ Full type safety with perfect type inference
|
|
29
|
+
- **๐ Production Ready** โ Battle-tested in real applications
|
|
30
|
+
|
|
31
|
+
### Advanced Capabilities
|
|
32
|
+
- **๐งฉ Middleware System** โ Extend functionality with logging, persistence, validation, and more
|
|
33
|
+
- **๐ก Direct State Access** โ `get()` function for reading state outside components
|
|
34
|
+
- **๐ฏ Selective Subscriptions** โ Components only re-render when their data changes
|
|
35
|
+
- **โ๏ธ Fully Extensible** โ Build custom middleware for any use case
|
|
36
|
+
- **๐งช Easy Testing** โ Simple to test stores with middleware and async operations
|
|
37
|
+
- **๐ Framework Agnostic** โ Create middleware once, use everywhere
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## ๐ฆ Installation
|
|
30
42
|
|
|
31
|
-
|
|
43
|
+
Choose your favorite package manager:
|
|
32
44
|
|
|
33
45
|
```bash
|
|
46
|
+
# npm
|
|
47
|
+
npm install zustic
|
|
48
|
+
|
|
49
|
+
# yarn
|
|
50
|
+
yarn add zustic
|
|
51
|
+
|
|
52
|
+
# pnpm
|
|
34
53
|
pnpm add zustic
|
|
35
54
|
```
|
|
36
55
|
|
|
37
|
-
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## ๐ค Why Zustic?
|
|
59
|
+
|
|
60
|
+
### Size & Performance
|
|
61
|
+
| Metric | Zustic | Redux | Zustand | Context API |
|
|
62
|
+
|--------|--------|-------|---------|-------------|
|
|
63
|
+
| **Bundle Size** | ~500B | ~6KB | ~2KB | Built-in |
|
|
64
|
+
| **Performance** | โก Optimized | Good | โก Optimized | โ ๏ธ Re-renders |
|
|
65
|
+
| **Dependencies** | 0 | 0 | 0 | 0 |
|
|
66
|
+
|
|
67
|
+
### Developer Experience
|
|
68
|
+
- **Ultra-Simple API**: Master everything in 5 minutes
|
|
69
|
+
- **Zero Boilerplate**: No actions, reducers, or providers
|
|
70
|
+
- **TypeScript Native**: Perfect type inference out of the box
|
|
71
|
+
- **Great DX**: Intuitive `create()`, `set()`, `get()` functions
|
|
72
|
+
|
|
73
|
+
### Comparison with Other Libraries
|
|
74
|
+
|
|
75
|
+
| Feature | Zustic | Redux | Zustand | Context API |
|
|
76
|
+
|---------|--------|-------|---------|-------------|
|
|
77
|
+
| Bundle Size | ~500B โ
| ~6KB | ~2KB | 0B |
|
|
78
|
+
| Learning Curve | โญ Easy | โญโญโญโญโญ Hard | โญโญ Easy | โญโญโญ Medium |
|
|
79
|
+
| Boilerplate | Minimal โ
| Massive | Minimal | Some |
|
|
80
|
+
| TypeScript | Excellent โ
| Good | Good | Good |
|
|
81
|
+
| Middleware | Built-in โ
| Required | Optional | โ No |
|
|
82
|
+
| API Simplicity | Very Simple โ
| Complex | Simple | Medium |
|
|
83
|
+
|
|
84
|
+
---
|
|
38
85
|
|
|
39
|
-
|
|
86
|
+
## ๐ Quick Start
|
|
87
|
+
|
|
88
|
+
### 1. Create Your Store
|
|
40
89
|
|
|
41
90
|
```typescript
|
|
42
91
|
import { create } from 'zustic';
|
|
@@ -56,7 +105,7 @@ export const useCounter = create<CounterStore>((set) => ({
|
|
|
56
105
|
}));
|
|
57
106
|
```
|
|
58
107
|
|
|
59
|
-
###
|
|
108
|
+
### 2. Use in Your Component
|
|
60
109
|
|
|
61
110
|
```typescript
|
|
62
111
|
import { useCounter } from './store';
|
|
@@ -67,9 +116,9 @@ function Counter() {
|
|
|
67
116
|
return (
|
|
68
117
|
<div>
|
|
69
118
|
<p>Count: {count}</p>
|
|
70
|
-
<button onClick={inc}
|
|
71
|
-
<button onClick={dec}
|
|
72
|
-
<button onClick={reset}
|
|
119
|
+
<button onClick={inc}>โ Increment</button>
|
|
120
|
+
<button onClick={dec}>โ Decrement</button>
|
|
121
|
+
<button onClick={reset}>๐ Reset</button>
|
|
73
122
|
</div>
|
|
74
123
|
);
|
|
75
124
|
}
|
|
@@ -77,363 +126,354 @@ function Counter() {
|
|
|
77
126
|
export default Counter;
|
|
78
127
|
```
|
|
79
128
|
|
|
80
|
-
|
|
129
|
+
That's it! No providers, no boilerplate, just pure state management.
|
|
81
130
|
|
|
82
|
-
|
|
131
|
+
---
|
|
83
132
|
|
|
84
|
-
|
|
133
|
+
## ๐ Core Concepts
|
|
85
134
|
|
|
86
|
-
|
|
135
|
+
### Create a Store
|
|
87
136
|
|
|
88
|
-
|
|
89
|
-
- A function that receives the `set` function and returns the initial state object
|
|
90
|
-
- The `set` function accepts either a partial state object or a function that takes the current state and returns a partial state object
|
|
137
|
+
The `create` function is the heart of Zustic:
|
|
91
138
|
|
|
92
|
-
|
|
139
|
+
```typescript
|
|
140
|
+
const useStore = create<StoreType>((set, get) => ({
|
|
141
|
+
// Your state and actions
|
|
142
|
+
}));
|
|
143
|
+
```
|
|
93
144
|
|
|
94
|
-
|
|
145
|
+
- **`set`**: Update state (supports partial updates and functions)
|
|
146
|
+
- **`get`**: Read current state (works outside components)
|
|
95
147
|
|
|
96
|
-
|
|
148
|
+
### Reading State in Components
|
|
97
149
|
|
|
98
|
-
|
|
150
|
+
```typescript
|
|
151
|
+
function Component() {
|
|
152
|
+
// Subscribe to entire store
|
|
153
|
+
const state = useStore();
|
|
154
|
+
|
|
155
|
+
// Or subscribe to specific properties (optimized)
|
|
156
|
+
const count = useStore((state) => state.count);
|
|
157
|
+
|
|
158
|
+
return <div>{count}</div>;
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
<!--
|
|
162
|
+
### Reading State Outside Components
|
|
99
163
|
|
|
100
|
-
|
|
164
|
+
```typescript
|
|
165
|
+
// In event handlers, callbacks, or services
|
|
166
|
+
const currentState = useStore.get();
|
|
167
|
+
console.log(currentState.count);
|
|
168
|
+
```
|
|
101
169
|
|
|
102
|
-
###
|
|
170
|
+
### Updating State
|
|
103
171
|
|
|
104
172
|
```typescript
|
|
105
|
-
|
|
173
|
+
// Partial update
|
|
174
|
+
useStore.set({ count: 5 });
|
|
106
175
|
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
setUser: (user) => set({ user }),
|
|
111
|
-
clearUser: () => set({ user: null }),
|
|
176
|
+
// Functional update with access to current state
|
|
177
|
+
useStore.set((state) => ({
|
|
178
|
+
count: state.count + 1
|
|
112
179
|
}));
|
|
113
180
|
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
todos: [...state.todos, todo]
|
|
119
|
-
})),
|
|
120
|
-
removeTodo: (id) => set((state) => ({
|
|
121
|
-
todos: state.todos.filter(t => t.id !== id)
|
|
122
|
-
})),
|
|
181
|
+
// Async updates
|
|
182
|
+
useStore.set(async (state) => ({
|
|
183
|
+
data: await fetchData(),
|
|
184
|
+
loading: false
|
|
123
185
|
}));
|
|
186
|
+
``` -->
|
|
124
187
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
<>
|
|
132
|
-
<User />
|
|
133
|
-
<TodoList />
|
|
134
|
-
</>
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
```
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## ๐งฉ Middleware System
|
|
191
|
+
|
|
192
|
+
Extend Zustic with powerful middleware for logging, persistence, validation, and more.
|
|
138
193
|
|
|
139
|
-
###
|
|
194
|
+
### Logger Middleware
|
|
140
195
|
|
|
141
196
|
```typescript
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
removeFromCart: (itemId) => set((state) => ({
|
|
153
|
-
cart: state.cart.filter(item => item.id !== itemId),
|
|
154
|
-
total: state.total - state.cart.find(item => item.id === itemId)?.price || 0,
|
|
155
|
-
})),
|
|
156
|
-
|
|
157
|
-
clearCart: () => set({
|
|
158
|
-
cart: [],
|
|
159
|
-
total: 0,
|
|
197
|
+
const logger = <T extends object>(): Middleware<T> => (set, get) => (next) => async (partial) => {
|
|
198
|
+
console.log('๐ต Previous State:', get());
|
|
199
|
+
await next(partial);
|
|
200
|
+
console.log('๐ข New State:', get());
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export const useStore = create<StoreType>(
|
|
204
|
+
(set) => ({
|
|
205
|
+
count: 0,
|
|
206
|
+
inc: () => set((state) => ({ count: state.count + 1 })),
|
|
160
207
|
}),
|
|
161
|
-
|
|
208
|
+
[logger()]
|
|
209
|
+
);
|
|
162
210
|
```
|
|
163
211
|
|
|
164
|
-
###
|
|
212
|
+
### Persistence Middleware
|
|
165
213
|
|
|
166
214
|
```typescript
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
scores: [...state.scores, score],
|
|
172
|
-
})),
|
|
173
|
-
|
|
174
|
-
// You can compute values directly in the component
|
|
175
|
-
// or create selector functions
|
|
176
|
-
getAverage: (state) => {
|
|
177
|
-
if (state.scores.length === 0) return 0;
|
|
178
|
-
return state.scores.reduce((a, b) => a + b, 0) / state.scores.length;
|
|
179
|
-
},
|
|
180
|
-
}));
|
|
215
|
+
const persist = <T extends object>(): Middleware<T> => (set, get) => (next) => async (partial) => {
|
|
216
|
+
await next(partial);
|
|
217
|
+
localStorage.setItem('store', JSON.stringify(get()));
|
|
218
|
+
};
|
|
181
219
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
220
|
+
export const useStore = create<StoreType>(
|
|
221
|
+
(set) => ({
|
|
222
|
+
count: 0,
|
|
223
|
+
inc: () => set((state) => ({ count: state.count + 1 })),
|
|
224
|
+
}),
|
|
225
|
+
[persist()]
|
|
226
|
+
);
|
|
188
227
|
```
|
|
189
228
|
|
|
190
|
-
###
|
|
229
|
+
### Validation Middleware
|
|
191
230
|
|
|
192
231
|
```typescript
|
|
193
|
-
|
|
194
|
-
|
|
232
|
+
const validate = <T extends object>(): Middleware<T> => (set, get) => (next) => async (partial) => {
|
|
233
|
+
// Validate before updating
|
|
234
|
+
if (typeof partial === 'object' && partial.count < 0) {
|
|
235
|
+
console.warn('Invalid state update');
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
await next(partial);
|
|
239
|
+
};
|
|
195
240
|
|
|
196
|
-
export const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
})
|
|
241
|
+
export const useStore = create<StoreType>(
|
|
242
|
+
(set) => ({
|
|
243
|
+
count: 0,
|
|
244
|
+
inc: () => set((state) => ({ count: state.count + 1 })),
|
|
245
|
+
}),
|
|
246
|
+
[validate()]
|
|
247
|
+
);
|
|
201
248
|
```
|
|
202
249
|
|
|
250
|
+
### Multiple Middleware
|
|
251
|
+
|
|
203
252
|
```typescript
|
|
204
|
-
|
|
205
|
-
|
|
253
|
+
export const useStore = create<StoreType>(
|
|
254
|
+
(set) => ({
|
|
255
|
+
count: 0,
|
|
256
|
+
inc: () => set((state) => ({ count: state.count + 1 })),
|
|
257
|
+
}),
|
|
258
|
+
[logger(), persist(), validate()]
|
|
259
|
+
);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
206
263
|
|
|
207
|
-
|
|
264
|
+
## ๐ฑ Multi-Platform Examples
|
|
208
265
|
|
|
209
|
-
|
|
210
|
-
const { count, increment, decrement } = useCounterStore();
|
|
266
|
+
### React Web
|
|
211
267
|
|
|
268
|
+
```typescript
|
|
269
|
+
import { create } from 'zustic';
|
|
270
|
+
|
|
271
|
+
const useStore = create((set) => ({
|
|
272
|
+
count: 0,
|
|
273
|
+
inc: () => set((state) => ({ count: state.count + 1 })),
|
|
274
|
+
}));
|
|
275
|
+
|
|
276
|
+
export default function App() {
|
|
277
|
+
const { count, inc } = useStore();
|
|
212
278
|
return (
|
|
213
|
-
<
|
|
214
|
-
<
|
|
215
|
-
<button onClick={
|
|
216
|
-
|
|
217
|
-
</main>
|
|
279
|
+
<div>
|
|
280
|
+
<p>{count}</p>
|
|
281
|
+
<button onClick={inc}>Increment</button>
|
|
282
|
+
</div>
|
|
218
283
|
);
|
|
219
284
|
}
|
|
220
285
|
```
|
|
221
286
|
|
|
222
|
-
###
|
|
287
|
+
### React Native
|
|
223
288
|
|
|
224
289
|
```typescript
|
|
225
290
|
import { create } from 'zustic';
|
|
226
|
-
import { View, Text,
|
|
291
|
+
import { View, Text, Button } from 'react-native';
|
|
227
292
|
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
293
|
+
const useStore = create((set) => ({
|
|
294
|
+
count: 0,
|
|
295
|
+
inc: () => set((state) => ({ count: state.count + 1 })),
|
|
231
296
|
}));
|
|
232
297
|
|
|
233
|
-
function App() {
|
|
234
|
-
const {
|
|
235
|
-
|
|
298
|
+
export default function App() {
|
|
299
|
+
const { count, inc } = useStore();
|
|
236
300
|
return (
|
|
237
|
-
<View
|
|
238
|
-
<Text>{
|
|
239
|
-
<
|
|
240
|
-
<Text>Toggle Theme</Text>
|
|
241
|
-
</TouchableOpacity>
|
|
301
|
+
<View>
|
|
302
|
+
<Text>{count}</Text>
|
|
303
|
+
<Button title="Increment" onPress={inc} />
|
|
242
304
|
</View>
|
|
243
305
|
);
|
|
244
306
|
}
|
|
245
307
|
```
|
|
246
308
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
### 1. **Organize Stores**
|
|
250
|
-
Keep your stores organized in a dedicated directory:
|
|
251
|
-
|
|
252
|
-
```
|
|
253
|
-
src/
|
|
254
|
-
โโโ stores/
|
|
255
|
-
โ โโโ counterStore.ts
|
|
256
|
-
โ โโโ userStore.ts
|
|
257
|
-
โ โโโ index.ts
|
|
258
|
-
โโโ components/
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
### 2. **Type Your Store**
|
|
262
|
-
Always define proper TypeScript types for better type safety:
|
|
309
|
+
### Next.js
|
|
263
310
|
|
|
264
311
|
```typescript
|
|
265
|
-
|
|
266
|
-
count: number;
|
|
267
|
-
inc: () => void;
|
|
268
|
-
dec: () => void;
|
|
269
|
-
}
|
|
312
|
+
'use client';
|
|
270
313
|
|
|
271
|
-
|
|
314
|
+
import { create } from 'zustic';
|
|
315
|
+
|
|
316
|
+
const useStore = create((set) => ({
|
|
272
317
|
count: 0,
|
|
273
318
|
inc: () => set((state) => ({ count: state.count + 1 })),
|
|
274
|
-
dec: () => set((state) => ({ count: state.count - 1 })),
|
|
275
319
|
}));
|
|
276
|
-
```
|
|
277
320
|
|
|
278
|
-
|
|
279
|
-
|
|
321
|
+
export default function Page() {
|
|
322
|
+
const { count, inc } = useStore();
|
|
323
|
+
return (
|
|
324
|
+
<div>
|
|
325
|
+
<p>{count}</p>
|
|
326
|
+
<button onClick={inc}>Increment</button>
|
|
327
|
+
</div>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
```
|
|
280
331
|
|
|
281
|
-
|
|
282
|
-
// โ Avoid deeply nested structures
|
|
283
|
-
const state = { user: { profile: { settings: { theme: 'dark' } } } };
|
|
332
|
+
---
|
|
284
333
|
|
|
285
|
-
|
|
286
|
-
const state = { userTheme: 'dark' };
|
|
287
|
-
```
|
|
334
|
+
## ๐งช Testing
|
|
288
335
|
|
|
289
|
-
|
|
290
|
-
Always return new objects instead of mutating state:
|
|
336
|
+
Zustic stores are easy to test:
|
|
291
337
|
|
|
292
338
|
```typescript
|
|
293
|
-
|
|
294
|
-
set((state) => {
|
|
295
|
-
state.items.push(newItem);
|
|
296
|
-
return state;
|
|
297
|
-
});
|
|
339
|
+
import { create } from 'zustic';
|
|
298
340
|
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
|
|
341
|
+
// Your store
|
|
342
|
+
const useStore = create((set) => ({
|
|
343
|
+
count: 0,
|
|
344
|
+
inc: () => set((state) => ({ count: state.count + 1 })),
|
|
345
|
+
reset: () => set({ count: 0 }),
|
|
302
346
|
}));
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
## Performance Tips
|
|
306
347
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
348
|
+
// Test it
|
|
349
|
+
describe('Counter Store', () => {
|
|
350
|
+
it('should increment count', () => {
|
|
351
|
+
useStore.set({ count: 0 });
|
|
352
|
+
useStore.get().inc();
|
|
353
|
+
expect(useStore.get().count).toBe(1);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should reset count', () => {
|
|
357
|
+
useStore.set({ count: 5 });
|
|
358
|
+
useStore.get().reset();
|
|
359
|
+
expect(useStore.get().count).toBe(0);
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
```
|
|
311
363
|
|
|
312
|
-
|
|
364
|
+
---
|
|
313
365
|
|
|
314
|
-
|
|
366
|
+
## ๐ก Advanced Examples
|
|
315
367
|
|
|
316
|
-
|
|
317
|
-
- Firefox (latest)
|
|
318
|
-
- Safari (latest)
|
|
319
|
-
- Mobile browsers supporting React Native
|
|
368
|
+
### Async State
|
|
320
369
|
|
|
321
|
-
|
|
370
|
+
```typescript
|
|
371
|
+
const useUserStore = create((set, get) => ({
|
|
372
|
+
user: null,
|
|
373
|
+
loading: false,
|
|
374
|
+
error: null,
|
|
375
|
+
|
|
376
|
+
fetchUser: async (id: string) => {
|
|
377
|
+
set({ loading: true });
|
|
378
|
+
try {
|
|
379
|
+
const response = await fetch(`/api/users/${id}`);
|
|
380
|
+
const user = await response.json();
|
|
381
|
+
set({ user, loading: false, error: null });
|
|
382
|
+
} catch (error) {
|
|
383
|
+
set({ error: error.message, loading: false });
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
}));
|
|
387
|
+
```
|
|
322
388
|
|
|
323
|
-
|
|
324
|
-
|---------|--------|---------|-------|-------------|
|
|
325
|
-
| Bundle Size | ~500B | ~2KB | ~7KB | - |
|
|
326
|
-
| Learning Curve | Very Easy | Easy | Hard | Medium |
|
|
327
|
-
| Boilerplate | Minimal | Minimal | Lots | Medium |
|
|
328
|
-
| DevTools | No | Yes | Yes | No |
|
|
329
|
-
| Middleware | No | Yes | Yes | No |
|
|
330
|
-
| TypeScript | โ
| โ
| โ
| โ
|
|
|
389
|
+
### Computed State
|
|
331
390
|
|
|
332
|
-
|
|
391
|
+
```typescript
|
|
392
|
+
const useCartStore = create((set, get) => ({
|
|
393
|
+
items: [],
|
|
394
|
+
|
|
395
|
+
addItem: (item) => set((state) => ({
|
|
396
|
+
items: [...state.items, item],
|
|
397
|
+
})),
|
|
398
|
+
|
|
399
|
+
get total() {
|
|
400
|
+
return get().items.reduce((sum, item) => sum + item.price, 0);
|
|
401
|
+
},
|
|
402
|
+
}));
|
|
403
|
+
```
|
|
333
404
|
|
|
334
|
-
###
|
|
335
|
-
Make sure you're using the `set` function correctly. Always return a new object:
|
|
405
|
+
### Nested Stores
|
|
336
406
|
|
|
337
407
|
```typescript
|
|
338
|
-
|
|
339
|
-
|
|
408
|
+
const useAuthStore = create((set) => ({
|
|
409
|
+
user: null,
|
|
410
|
+
login: (user) => set({ user }),
|
|
411
|
+
logout: () => set({ user: null }),
|
|
412
|
+
}));
|
|
340
413
|
|
|
341
|
-
|
|
342
|
-
|
|
414
|
+
const useAppStore = create((set) => ({
|
|
415
|
+
auth: useAuthStore,
|
|
416
|
+
theme: 'light',
|
|
417
|
+
}));
|
|
343
418
|
```
|
|
344
419
|
|
|
345
|
-
|
|
346
|
-
Ensure you're using the hook at the top level of your component:
|
|
420
|
+
---
|
|
347
421
|
|
|
348
|
-
|
|
349
|
-
// โ Bad
|
|
350
|
-
if (condition) {
|
|
351
|
-
const state = useStore();
|
|
352
|
-
}
|
|
422
|
+
## ๐ Resources
|
|
353
423
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
424
|
+
- ๐ **[Full Documentation](https://zustic.github.io/)** - Complete API reference and guides
|
|
425
|
+
- ๐ **[GitHub Issues](https://github.com/DeveloperRejaul/zustic/issues)** - Report bugs and request features
|
|
426
|
+
- ๐ฌ **[Discussions](https://github.com/DeveloperRejaul/zustic/discussions)** - Ask questions and share ideas
|
|
427
|
+
- ๐ฆ **[NPM Package](https://npm.im/zustic)** - Install and view package info
|
|
357
428
|
|
|
358
|
-
|
|
429
|
+
---
|
|
359
430
|
|
|
360
|
-
|
|
431
|
+
## ๐ API Reference
|
|
361
432
|
|
|
362
|
-
|
|
363
|
-
```typescript
|
|
364
|
-
const CounterContext = createContext();
|
|
433
|
+
### `create<T>(initializer, middlewares?)`
|
|
365
434
|
|
|
366
|
-
|
|
367
|
-
const [count, setCount] = useState(0);
|
|
368
|
-
|
|
369
|
-
return (
|
|
370
|
-
<CounterContext.Provider value={{ count, setCount }}>
|
|
371
|
-
{children}
|
|
372
|
-
</CounterContext.Provider>
|
|
373
|
-
);
|
|
374
|
-
}
|
|
435
|
+
Creates a new store with state and actions.
|
|
375
436
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
437
|
+
**Parameters:**
|
|
438
|
+
- `initializer` - Function that receives `set` and `get`, returns initial state
|
|
439
|
+
- `middlewares` (optional) - Array of middleware functions
|
|
440
|
+
|
|
441
|
+
**Returns:**
|
|
442
|
+
- A hook function that provides access to store state and actions
|
|
380
443
|
|
|
381
|
-
|
|
444
|
+
**Example:**
|
|
382
445
|
```typescript
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
446
|
+
const useStore = create((set, get) => ({
|
|
447
|
+
value: 0,
|
|
448
|
+
increment: () => set((state) => ({ value: state.value + 1 })),
|
|
449
|
+
getValue: () => get().value,
|
|
386
450
|
}));
|
|
387
451
|
```
|
|
388
452
|
|
|
389
|
-
|
|
453
|
+
---
|
|
390
454
|
|
|
391
|
-
|
|
392
|
-
```typescript
|
|
393
|
-
const counterSlice = createSlice({
|
|
394
|
-
name: 'counter',
|
|
395
|
-
initialState: { count: 0 },
|
|
396
|
-
reducers: {
|
|
397
|
-
increment: (state) => { state.count += 1; },
|
|
398
|
-
},
|
|
399
|
-
});
|
|
455
|
+
## ๐ค Contributing
|
|
400
456
|
|
|
401
|
-
|
|
402
|
-
export default useSelector((state) => state.counter);
|
|
403
|
-
```
|
|
457
|
+
Contributions are welcome! Please feel free to submit a Pull Request to the [GitHub repository](https://github.com/DeveloperRejaul/zustic).
|
|
404
458
|
|
|
405
|
-
|
|
406
|
-
```typescript
|
|
407
|
-
export const useCounter = create((set) => ({
|
|
408
|
-
count: 0,
|
|
409
|
-
increment: () => set((state) => ({ count: state.count + 1 })),
|
|
410
|
-
}));
|
|
411
|
-
```
|
|
459
|
+
---
|
|
412
460
|
|
|
413
|
-
##
|
|
461
|
+
## ๐ License
|
|
414
462
|
|
|
415
|
-
|
|
463
|
+
MIT License ยฉ 2024 [Rejaul Karim](https://github.com/DeveloperRejaul)
|
|
416
464
|
|
|
417
|
-
|
|
465
|
+
---
|
|
418
466
|
|
|
419
|
-
|
|
467
|
+
## ๐จโ๐ป Author
|
|
420
468
|
|
|
421
|
-
|
|
469
|
+
Created by **Rejaul Karim** - [GitHub](https://github.com/DeveloperRejaul)
|
|
422
470
|
|
|
423
|
-
|
|
424
|
-
- ๐ [Bug Reports](https://github.com/DeveloperRejaul/zustic/issues)
|
|
425
|
-
- ๐ฌ [Discussions](https://github.com/DeveloperRejaul/zustic/discussions)
|
|
471
|
+
---
|
|
426
472
|
|
|
427
|
-
|
|
473
|
+
<div align="center">
|
|
428
474
|
|
|
429
|
-
|
|
430
|
-
- [Jotai](https://github.com/pmndrs/jotai) - Primitive and flexible state management for React
|
|
431
|
-
- [Recoil](https://recoiljs.org/) - A state management library for React
|
|
475
|
+
### Made with โค๏ธ for the React community
|
|
432
476
|
|
|
433
|
-
|
|
477
|
+
โญ Star us on [GitHub](https://github.com/DeveloperRejaul/zustic) if you find this helpful!
|
|
434
478
|
|
|
435
|
-
|
|
436
|
-
- Initial release
|
|
437
|
-
- Basic state management with `create` function
|
|
438
|
-
- TypeScript support
|
|
439
|
-
- React, React Native, and Next.js compatibility
|
|
479
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useSyncExternalStore as p}from"react";function d(a,n=[]){let e,t=[],s=r=>{let o=typeof r=="function"?r(e):r;e={...e,...o},t.forEach(T=>T())},i=()=>e,c=l(s,i,n);e=a(c,i);let S=r=>(t.push(r),()=>{t=t.filter(o=>o!==r)});return()=>p(S,i)}var l=(a,n,e)=>!e||e.length===0?a:e.reduceRight((t,s)=>s(a,n)(t),a);export{d as a};
|
package/dist/index.js
CHANGED
|
@@ -1,73 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
"use client";
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
9
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
10
|
-
var __spreadValues = (a, b) => {
|
|
11
|
-
for (var prop in b || (b = {}))
|
|
12
|
-
if (__hasOwnProp.call(b, prop))
|
|
13
|
-
__defNormalProp(a, prop, b[prop]);
|
|
14
|
-
if (__getOwnPropSymbols)
|
|
15
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
16
|
-
if (__propIsEnum.call(b, prop))
|
|
17
|
-
__defNormalProp(a, prop, b[prop]);
|
|
18
|
-
}
|
|
19
|
-
return a;
|
|
20
|
-
};
|
|
21
|
-
var __export = (target, all) => {
|
|
22
|
-
for (var name in all)
|
|
23
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
24
|
-
};
|
|
25
|
-
var __copyProps = (to, from, except, desc) => {
|
|
26
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
27
|
-
for (let key of __getOwnPropNames(from))
|
|
28
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
29
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
30
|
-
}
|
|
31
|
-
return to;
|
|
32
|
-
};
|
|
33
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
34
|
-
|
|
35
|
-
// src/index.ts
|
|
36
|
-
var index_exports = {};
|
|
37
|
-
__export(index_exports, {
|
|
38
|
-
create: () => create
|
|
39
|
-
});
|
|
40
|
-
module.exports = __toCommonJS(index_exports);
|
|
41
|
-
var import_react = require("react");
|
|
42
|
-
function create(initializer, middlewares = []) {
|
|
43
|
-
let state;
|
|
44
|
-
let listeners = [];
|
|
45
|
-
const setState = (partial) => {
|
|
46
|
-
const partialState = typeof partial === "function" ? partial(state) : partial;
|
|
47
|
-
state = __spreadValues(__spreadValues({}, state), partialState);
|
|
48
|
-
listeners.forEach((l) => l());
|
|
49
|
-
};
|
|
50
|
-
const getState = () => state;
|
|
51
|
-
const setStateWithMiddleware = applyMiddleware(setState, getState, middlewares);
|
|
52
|
-
state = initializer(setStateWithMiddleware, getState);
|
|
53
|
-
const subscribe = (listener) => {
|
|
54
|
-
listeners.push(listener);
|
|
55
|
-
return () => {
|
|
56
|
-
listeners = listeners.filter((l) => l !== listener);
|
|
57
|
-
};
|
|
58
|
-
};
|
|
59
|
-
return () => (0, import_react.useSyncExternalStore)(subscribe, getState);
|
|
60
|
-
}
|
|
61
|
-
var applyMiddleware = (set, get, middlewares) => {
|
|
62
|
-
if (!middlewares || middlewares.length === 0) {
|
|
63
|
-
return set;
|
|
64
|
-
}
|
|
65
|
-
return middlewares.reduceRight(
|
|
66
|
-
(next, mw) => mw(set, get)(next),
|
|
67
|
-
set
|
|
68
|
-
);
|
|
69
|
-
};
|
|
70
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
71
|
-
0 && (module.exports = {
|
|
72
|
-
create
|
|
73
|
-
});
|
|
1
|
+
"use strict";var c=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var y=(t,r)=>{for(var e in r)c(t,e,{get:r[e],enumerable:!0})},M=(t,r,e,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of f(r))!m.call(t,o)&&o!==e&&c(t,o,{get:()=>r[o],enumerable:!(a=u(r,o))||a.enumerable});return t};var P=t=>M(c({},"__esModule",{value:!0}),t);var x={};y(x,{create:()=>S});module.exports=P(x);var p=require("react");function S(t,r=[]){let e,a=[],o=s=>{let i=typeof s=="function"?s(e):s;e={...e,...i},a.forEach(l=>l())},n=()=>e,T=h(o,n,r);e=t(T,n);let d=s=>(a.push(s),()=>{a=a.filter(i=>i!==s)});return()=>(0,p.useSyncExternalStore)(d,n)}var h=(t,r,e)=>!e||e.length===0?t:e.reduceRight((a,o)=>o(t,r)(a),t);0&&(module.exports={create});
|
package/dist/index.mjs
CHANGED
|
@@ -1,51 +1 @@
|
|
|
1
|
-
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
4
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
6
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
-
var __spreadValues = (a, b) => {
|
|
8
|
-
for (var prop in b || (b = {}))
|
|
9
|
-
if (__hasOwnProp.call(b, prop))
|
|
10
|
-
__defNormalProp(a, prop, b[prop]);
|
|
11
|
-
if (__getOwnPropSymbols)
|
|
12
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
13
|
-
if (__propIsEnum.call(b, prop))
|
|
14
|
-
__defNormalProp(a, prop, b[prop]);
|
|
15
|
-
}
|
|
16
|
-
return a;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// src/index.ts
|
|
20
|
-
import { useSyncExternalStore } from "react";
|
|
21
|
-
function create(initializer, middlewares = []) {
|
|
22
|
-
let state;
|
|
23
|
-
let listeners = [];
|
|
24
|
-
const setState = (partial) => {
|
|
25
|
-
const partialState = typeof partial === "function" ? partial(state) : partial;
|
|
26
|
-
state = __spreadValues(__spreadValues({}, state), partialState);
|
|
27
|
-
listeners.forEach((l) => l());
|
|
28
|
-
};
|
|
29
|
-
const getState = () => state;
|
|
30
|
-
const setStateWithMiddleware = applyMiddleware(setState, getState, middlewares);
|
|
31
|
-
state = initializer(setStateWithMiddleware, getState);
|
|
32
|
-
const subscribe = (listener) => {
|
|
33
|
-
listeners.push(listener);
|
|
34
|
-
return () => {
|
|
35
|
-
listeners = listeners.filter((l) => l !== listener);
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
return () => useSyncExternalStore(subscribe, getState);
|
|
39
|
-
}
|
|
40
|
-
var applyMiddleware = (set, get, middlewares) => {
|
|
41
|
-
if (!middlewares || middlewares.length === 0) {
|
|
42
|
-
return set;
|
|
43
|
-
}
|
|
44
|
-
return middlewares.reduceRight(
|
|
45
|
-
(next, mw) => mw(set, get)(next),
|
|
46
|
-
set
|
|
47
|
-
);
|
|
48
|
-
};
|
|
49
|
-
export {
|
|
50
|
-
create
|
|
51
|
-
};
|
|
1
|
+
import{a as e}from"./chunk-SISWF3T4.mjs";export{e as create};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
type QueryFnObj = {
|
|
2
|
+
url: string;
|
|
3
|
+
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
4
|
+
body?: any;
|
|
5
|
+
headers?: Record<string, any>;
|
|
6
|
+
};
|
|
7
|
+
type QueryFnReturn = string | QueryFnObj;
|
|
8
|
+
type QueryFn<Arg = any> = (arg: Arg) => QueryFnReturn;
|
|
9
|
+
type MainQueryReturnTypes = Promise<{
|
|
10
|
+
data: any;
|
|
11
|
+
error?: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
error: any;
|
|
14
|
+
data?: undefined;
|
|
15
|
+
}>;
|
|
16
|
+
type ApiOption<Arg, R> = {
|
|
17
|
+
transformResponse?: (currData: any, preData: any) => Promise<R> | R;
|
|
18
|
+
transformError?: (currError: any, preError: any) => Promise<any> | any;
|
|
19
|
+
transformBody?: (body: Arg) => Promise<any> | any;
|
|
20
|
+
transformHeader?: (header: Record<string, any>) => Promise<Record<string, any>> | Record<string, any>;
|
|
21
|
+
onError?: (err: any) => Promise<void> | void;
|
|
22
|
+
onSuccess?: (data: R) => Promise<void> | void;
|
|
23
|
+
queryFnc?: (arg: Arg, baseQuery: CreateApiParams<any>['baseQuery']) => MainQueryReturnTypes;
|
|
24
|
+
middlewares?: ApiMiddleware[];
|
|
25
|
+
plugins?: ApiPlugin[];
|
|
26
|
+
};
|
|
27
|
+
type QueryDef<Arg, Result> = {
|
|
28
|
+
type: 'query';
|
|
29
|
+
queryFn?: QueryFn<Arg>;
|
|
30
|
+
} & ApiOption<Arg, Result>;
|
|
31
|
+
type MutationDef<Arg, Result> = {
|
|
32
|
+
type: 'mutation';
|
|
33
|
+
queryFn?: QueryFn<Arg>;
|
|
34
|
+
} & ApiOption<Arg, Result>;
|
|
35
|
+
type EndpointDef = QueryDef<any, any> | MutationDef<any, any>;
|
|
36
|
+
type MainQueryHookResult<Result> = {
|
|
37
|
+
data?: Result;
|
|
38
|
+
isLoading: boolean;
|
|
39
|
+
isError: boolean;
|
|
40
|
+
isFetching: boolean;
|
|
41
|
+
isSuccess: boolean;
|
|
42
|
+
error: any;
|
|
43
|
+
reFetch: () => MainQueryReturnTypes;
|
|
44
|
+
};
|
|
45
|
+
type MainMutationState<Result> = {
|
|
46
|
+
data?: Result;
|
|
47
|
+
isLoading: boolean;
|
|
48
|
+
isError: boolean;
|
|
49
|
+
isSuccess: boolean;
|
|
50
|
+
error: any;
|
|
51
|
+
};
|
|
52
|
+
type EndpointsMap = Record<string, EndpointDef>;
|
|
53
|
+
type HooksFromEndpoints<T extends EndpointsMap> = {
|
|
54
|
+
[K in keyof T as T[K] extends {
|
|
55
|
+
type: 'query';
|
|
56
|
+
} ? `use${Capitalize<string & K>}Query` : `use${Capitalize<string & K>}Mutation`]: T[K] extends QueryDef<infer Arg, infer Result> ? (arg: Arg, option?: QueryHookOption) => MainQueryHookResult<Result> : T[K] extends MutationDef<infer Arg, infer Result> ? () => readonly [(arg: Arg) => Promise<Result>, MainMutationState<Result>] : never;
|
|
57
|
+
};
|
|
58
|
+
type BuilderType = {
|
|
59
|
+
query<Result, Arg = void>(config: {
|
|
60
|
+
query?: (arg: Arg) => QueryFnReturn;
|
|
61
|
+
} & ApiOption<Arg, Result>): QueryDef<Arg, Result>;
|
|
62
|
+
mutation<Result, Arg = void>(config: {
|
|
63
|
+
query?: (arg: Arg) => QueryFnObj;
|
|
64
|
+
} & ApiOption<Arg, Result>): MutationDef<Arg, Result>;
|
|
65
|
+
};
|
|
66
|
+
type BaseQueryReturn<Data = any, Error = any> = {
|
|
67
|
+
data: Data;
|
|
68
|
+
error?: undefined;
|
|
69
|
+
} | {
|
|
70
|
+
data?: undefined;
|
|
71
|
+
error: Error;
|
|
72
|
+
};
|
|
73
|
+
interface CreateApiParams<T extends EndpointsMap> {
|
|
74
|
+
baseQuery: (option: QueryFnReturn) => Promise<BaseQueryReturn>;
|
|
75
|
+
endpoints: (builder: BuilderType) => T;
|
|
76
|
+
clashTimeout?: number;
|
|
77
|
+
middlewares?: ApiMiddleware[];
|
|
78
|
+
plugins?: ApiPlugin[];
|
|
79
|
+
}
|
|
80
|
+
interface QueryHookOption {
|
|
81
|
+
skip: boolean;
|
|
82
|
+
}
|
|
83
|
+
type MiddlewareContext = {
|
|
84
|
+
arg: any;
|
|
85
|
+
def: any;
|
|
86
|
+
get: any;
|
|
87
|
+
set: any;
|
|
88
|
+
};
|
|
89
|
+
type ApiMiddleware = (ctx: MiddlewareContext, next: () => Promise<{
|
|
90
|
+
data?: any;
|
|
91
|
+
error?: any;
|
|
92
|
+
}>) => Promise<{
|
|
93
|
+
data?: any;
|
|
94
|
+
error?: any;
|
|
95
|
+
}>;
|
|
96
|
+
type ApiPlugin = {
|
|
97
|
+
name: string;
|
|
98
|
+
onInit?: (api: {
|
|
99
|
+
baseQuery: any;
|
|
100
|
+
endpoints: any;
|
|
101
|
+
}) => void;
|
|
102
|
+
beforeQuery?: (ctx: PluginContext) => void | Promise<void>;
|
|
103
|
+
middleware?: ApiMiddleware;
|
|
104
|
+
afterQuery?: (result: any, ctx: PluginContext) => void | Promise<void>;
|
|
105
|
+
onError?: (error: any, ctx: PluginContext) => void | Promise<void>;
|
|
106
|
+
};
|
|
107
|
+
type PluginContext = {
|
|
108
|
+
arg: any;
|
|
109
|
+
def: any;
|
|
110
|
+
get: any;
|
|
111
|
+
set: any;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
declare function createApi<T extends EndpointsMap>(params: CreateApiParams<T>): HooksFromEndpoints<T>;
|
|
115
|
+
|
|
116
|
+
export { type ApiMiddleware, type ApiPlugin, createApi };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
type QueryFnObj = {
|
|
2
|
+
url: string;
|
|
3
|
+
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
4
|
+
body?: any;
|
|
5
|
+
headers?: Record<string, any>;
|
|
6
|
+
};
|
|
7
|
+
type QueryFnReturn = string | QueryFnObj;
|
|
8
|
+
type QueryFn<Arg = any> = (arg: Arg) => QueryFnReturn;
|
|
9
|
+
type MainQueryReturnTypes = Promise<{
|
|
10
|
+
data: any;
|
|
11
|
+
error?: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
error: any;
|
|
14
|
+
data?: undefined;
|
|
15
|
+
}>;
|
|
16
|
+
type ApiOption<Arg, R> = {
|
|
17
|
+
transformResponse?: (currData: any, preData: any) => Promise<R> | R;
|
|
18
|
+
transformError?: (currError: any, preError: any) => Promise<any> | any;
|
|
19
|
+
transformBody?: (body: Arg) => Promise<any> | any;
|
|
20
|
+
transformHeader?: (header: Record<string, any>) => Promise<Record<string, any>> | Record<string, any>;
|
|
21
|
+
onError?: (err: any) => Promise<void> | void;
|
|
22
|
+
onSuccess?: (data: R) => Promise<void> | void;
|
|
23
|
+
queryFnc?: (arg: Arg, baseQuery: CreateApiParams<any>['baseQuery']) => MainQueryReturnTypes;
|
|
24
|
+
middlewares?: ApiMiddleware[];
|
|
25
|
+
plugins?: ApiPlugin[];
|
|
26
|
+
};
|
|
27
|
+
type QueryDef<Arg, Result> = {
|
|
28
|
+
type: 'query';
|
|
29
|
+
queryFn?: QueryFn<Arg>;
|
|
30
|
+
} & ApiOption<Arg, Result>;
|
|
31
|
+
type MutationDef<Arg, Result> = {
|
|
32
|
+
type: 'mutation';
|
|
33
|
+
queryFn?: QueryFn<Arg>;
|
|
34
|
+
} & ApiOption<Arg, Result>;
|
|
35
|
+
type EndpointDef = QueryDef<any, any> | MutationDef<any, any>;
|
|
36
|
+
type MainQueryHookResult<Result> = {
|
|
37
|
+
data?: Result;
|
|
38
|
+
isLoading: boolean;
|
|
39
|
+
isError: boolean;
|
|
40
|
+
isFetching: boolean;
|
|
41
|
+
isSuccess: boolean;
|
|
42
|
+
error: any;
|
|
43
|
+
reFetch: () => MainQueryReturnTypes;
|
|
44
|
+
};
|
|
45
|
+
type MainMutationState<Result> = {
|
|
46
|
+
data?: Result;
|
|
47
|
+
isLoading: boolean;
|
|
48
|
+
isError: boolean;
|
|
49
|
+
isSuccess: boolean;
|
|
50
|
+
error: any;
|
|
51
|
+
};
|
|
52
|
+
type EndpointsMap = Record<string, EndpointDef>;
|
|
53
|
+
type HooksFromEndpoints<T extends EndpointsMap> = {
|
|
54
|
+
[K in keyof T as T[K] extends {
|
|
55
|
+
type: 'query';
|
|
56
|
+
} ? `use${Capitalize<string & K>}Query` : `use${Capitalize<string & K>}Mutation`]: T[K] extends QueryDef<infer Arg, infer Result> ? (arg: Arg, option?: QueryHookOption) => MainQueryHookResult<Result> : T[K] extends MutationDef<infer Arg, infer Result> ? () => readonly [(arg: Arg) => Promise<Result>, MainMutationState<Result>] : never;
|
|
57
|
+
};
|
|
58
|
+
type BuilderType = {
|
|
59
|
+
query<Result, Arg = void>(config: {
|
|
60
|
+
query?: (arg: Arg) => QueryFnReturn;
|
|
61
|
+
} & ApiOption<Arg, Result>): QueryDef<Arg, Result>;
|
|
62
|
+
mutation<Result, Arg = void>(config: {
|
|
63
|
+
query?: (arg: Arg) => QueryFnObj;
|
|
64
|
+
} & ApiOption<Arg, Result>): MutationDef<Arg, Result>;
|
|
65
|
+
};
|
|
66
|
+
type BaseQueryReturn<Data = any, Error = any> = {
|
|
67
|
+
data: Data;
|
|
68
|
+
error?: undefined;
|
|
69
|
+
} | {
|
|
70
|
+
data?: undefined;
|
|
71
|
+
error: Error;
|
|
72
|
+
};
|
|
73
|
+
interface CreateApiParams<T extends EndpointsMap> {
|
|
74
|
+
baseQuery: (option: QueryFnReturn) => Promise<BaseQueryReturn>;
|
|
75
|
+
endpoints: (builder: BuilderType) => T;
|
|
76
|
+
clashTimeout?: number;
|
|
77
|
+
middlewares?: ApiMiddleware[];
|
|
78
|
+
plugins?: ApiPlugin[];
|
|
79
|
+
}
|
|
80
|
+
interface QueryHookOption {
|
|
81
|
+
skip: boolean;
|
|
82
|
+
}
|
|
83
|
+
type MiddlewareContext = {
|
|
84
|
+
arg: any;
|
|
85
|
+
def: any;
|
|
86
|
+
get: any;
|
|
87
|
+
set: any;
|
|
88
|
+
};
|
|
89
|
+
type ApiMiddleware = (ctx: MiddlewareContext, next: () => Promise<{
|
|
90
|
+
data?: any;
|
|
91
|
+
error?: any;
|
|
92
|
+
}>) => Promise<{
|
|
93
|
+
data?: any;
|
|
94
|
+
error?: any;
|
|
95
|
+
}>;
|
|
96
|
+
type ApiPlugin = {
|
|
97
|
+
name: string;
|
|
98
|
+
onInit?: (api: {
|
|
99
|
+
baseQuery: any;
|
|
100
|
+
endpoints: any;
|
|
101
|
+
}) => void;
|
|
102
|
+
beforeQuery?: (ctx: PluginContext) => void | Promise<void>;
|
|
103
|
+
middleware?: ApiMiddleware;
|
|
104
|
+
afterQuery?: (result: any, ctx: PluginContext) => void | Promise<void>;
|
|
105
|
+
onError?: (error: any, ctx: PluginContext) => void | Promise<void>;
|
|
106
|
+
};
|
|
107
|
+
type PluginContext = {
|
|
108
|
+
arg: any;
|
|
109
|
+
def: any;
|
|
110
|
+
get: any;
|
|
111
|
+
set: any;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
declare function createApi<T extends EndpointsMap>(params: CreateApiParams<T>): HooksFromEndpoints<T>;
|
|
115
|
+
|
|
116
|
+
export { type ApiMiddleware, type ApiPlugin, createApi };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var M=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var H=Object.prototype.hasOwnProperty;var C=(t,n)=>{for(var a in n)M(t,a,{get:n[a],enumerable:!0})},R=(t,n,a,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let u of k(n))!H.call(t,u)&&u!==a&&M(t,u,{get:()=>n[u],enumerable:!(r=L(n,u))||r.enumerable});return t};var O=t=>R(M({},"__esModule",{value:!0}),t);var D={};C(D,{createApi:()=>N});module.exports=O(D);var A=require("react");var P=require("react");function g(t,n=[]){let a,r=[],u=c=>{let i=typeof c=="function"?c(a):c;a={...a,...i},r.forEach(y=>y())},w=()=>a,F=B(u,w,n);a=t(F,w);let S=c=>(r.push(c),()=>{r=r.filter(i=>i!==c)});return()=>(0,P.useSyncExternalStore)(S,w)}var B=(t,n,a)=>!a||a.length===0?t:a.reduceRight((r,u)=>u(t,n)(r),t);function v(t){return t.charAt(0).toUpperCase()+t.slice(1)}var J=async(t,n,a,r,u,w,F)=>{var S,c,i,y,T,m,p;n({isLoading:!0});try{let e=null,o=null,s=a().cashExp,b=Date.now(),h=!1;if(F||JSON.stringify(a().arg||{})!==JSON.stringify(t||{})?h=!1:h=s>=b,h&&(e=a().data),!h&&(r!=null&&r.queryFnc)){n({isFetching:!0});let{data:l,error:E}=await((S=r==null?void 0:r.queryFnc)==null?void 0:S.call(r,t,u));l&&(e=l),E&&(o=E)}else{let l=r.queryFn(t);if(r!=null&&r.transformHeader&&(l.headers=await((c=r==null?void 0:r.transformHeader)==null?void 0:c.call(r,l==null?void 0:l.headers))),r!=null&&r.transformBody&&(l.body=await((i=r==null?void 0:r.transformBody)==null?void 0:i.call(r,l==null?void 0:l.body))),!h){n({isFetching:!0});let{data:E,error:q}=await u(l);E&&(e=E),q&&(o=q)}}return e&&(r!=null&&r.transformResponse&&(e=await((y=r.transformResponse)==null?void 0:y.call(r,e,a().data))),r!=null&&r.onSuccess&&await((T=r.onSuccess)==null?void 0:T.call(r,e))),o&&(r!=null&&r.transformError&&(o=await((m=r.transformError)==null?void 0:m.call(r,o,a().error))),r!=null&&r.onError&&await((p=r.onError)==null?void 0:p.call(r,o))),e?(n({data:e,isSuccess:!0,isLoading:!1,isFetching:!1,cashExp:h?s:Date.now()+w,arg:t}),{data:e}):(n({isLoading:!1,isSuccess:!1,isFetching:!1,isError:!0,error:o,arg:t}),{error:o})}catch(e){return n({isLoading:!1,isSuccess:!1,isFetching:!1,isError:!0,error:e,arg:t}),{error:e}}};async function x(t,n,a,r,u,w,F,S,c){var p,e,o;let i={arg:t,def:r,get:a,set:n};for(let s of c)await((p=s.beforeQuery)==null?void 0:p.call(s,i));let y=-1,T=async s=>{if(s<=y)throw new Error("next() called multiple times");y=s;let b=S[s];return b?b(i,()=>T(s+1)):J(t,n,a,r,u,w,F)},m=await T(0);for(let s of c)await((e=s.afterQuery)==null?void 0:e.call(s,m,i));if(m!=null&&m.error)for(let s of c)await((o=s.onError)==null?void 0:o.call(s,m.error,i));return m}function N(t){let{baseQuery:n,endpoints:a,clashTimeout:r=30*1e3,middlewares:u=[],plugins:w=[]}=t,S=a({query:i=>({type:"query",queryFn:i.query,...i}),mutation:i=>({type:"mutation",queryFn:i.query,...i})}),c={};for(let i in S){let y=S[i],T=`use${v(i)}`+(y.type==="query"?"Query":"Mutation"),m=g((p,e)=>({data:null,isLoading:!1,isError:!1,isFetching:!1,isSuccess:!1,error:null,arg:null,cashExp:0,query:o=>x(o,p,e,y,n,r,!1,[...u,...y.middlewares||[]],[...w,...y.plugins||[]]),reFetch:()=>{var o;return x((o=e())==null?void 0:o.arg,p,e,y,n,r,!0,[...u,...y.middlewares||[]],[...w,...y.plugins||[]])}}));y.type==="query"&&(c[T]=(p,e)=>{let{skip:o}=e||{},{query:s,error:b,isError:h,isLoading:l,isSuccess:E,reFetch:q,data:Q}=m();return(0,A.useEffect)(()=>{o||s(p)},[JSON.stringify(p||{})]),{error:b,isError:h,isLoading:l,isSuccess:E,data:Q,reFetch:q}}),y.type==="mutation"&&(c[T]=()=>{let{query:p,...e}=m();return[p,e]})}return c}0&&(module.exports={createApi});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as Q}from"../chunk-SISWF3T4.mjs";import{useEffect as k}from"react";function x(a){return a.charAt(0).toUpperCase()+a.slice(1)}var M=async(a,c,l,r,h,q,b)=>{var E,p,o,s,w,y,u;c({isLoading:!0});try{let n=null,t=null,i=l().cashExp,S=Date.now(),m=!1;if(b||JSON.stringify(l().arg||{})!==JSON.stringify(a||{})?m=!1:m=i>=S,m&&(n=l().data),!m&&(r!=null&&r.queryFnc)){c({isFetching:!0});let{data:e,error:F}=await((E=r==null?void 0:r.queryFnc)==null?void 0:E.call(r,a,h));e&&(n=e),F&&(t=F)}else{let e=r.queryFn(a);if(r!=null&&r.transformHeader&&(e.headers=await((p=r==null?void 0:r.transformHeader)==null?void 0:p.call(r,e==null?void 0:e.headers))),r!=null&&r.transformBody&&(e.body=await((o=r==null?void 0:r.transformBody)==null?void 0:o.call(r,e==null?void 0:e.body))),!m){c({isFetching:!0});let{data:F,error:A}=await h(e);F&&(n=F),A&&(t=A)}}return n&&(r!=null&&r.transformResponse&&(n=await((s=r.transformResponse)==null?void 0:s.call(r,n,l().data))),r!=null&&r.onSuccess&&await((w=r.onSuccess)==null?void 0:w.call(r,n))),t&&(r!=null&&r.transformError&&(t=await((y=r.transformError)==null?void 0:y.call(r,t,l().error))),r!=null&&r.onError&&await((u=r.onError)==null?void 0:u.call(r,t))),n?(c({data:n,isSuccess:!0,isLoading:!1,isFetching:!1,cashExp:m?i:Date.now()+q,arg:a}),{data:n}):(c({isLoading:!1,isSuccess:!1,isFetching:!1,isError:!0,error:t,arg:a}),{error:t})}catch(n){return c({isLoading:!1,isSuccess:!1,isFetching:!1,isError:!0,error:n,arg:a}),{error:n}}};async function T(a,c,l,r,h,q,b,E,p){var u,n,t;let o={arg:a,def:r,get:l,set:c};for(let i of p)await((u=i.beforeQuery)==null?void 0:u.call(i,o));let s=-1,w=async i=>{if(i<=s)throw new Error("next() called multiple times");s=i;let S=E[i];return S?S(o,()=>w(i+1)):M(a,c,l,r,h,q,b)},y=await w(0);for(let i of p)await((n=i.afterQuery)==null?void 0:n.call(i,y,o));if(y!=null&&y.error)for(let i of p)await((t=i.onError)==null?void 0:t.call(i,y.error,o));return y}function P(a){let{baseQuery:c,endpoints:l,clashTimeout:r=30*1e3,middlewares:h=[],plugins:q=[]}=a,E=l({query:o=>({type:"query",queryFn:o.query,...o}),mutation:o=>({type:"mutation",queryFn:o.query,...o})}),p={};for(let o in E){let s=E[o],w=`use${x(o)}`+(s.type==="query"?"Query":"Mutation"),y=Q((u,n)=>({data:null,isLoading:!1,isError:!1,isFetching:!1,isSuccess:!1,error:null,arg:null,cashExp:0,query:t=>T(t,u,n,s,c,r,!1,[...h,...s.middlewares||[]],[...q,...s.plugins||[]]),reFetch:()=>{var t;return T((t=n())==null?void 0:t.arg,u,n,s,c,r,!0,[...h,...s.middlewares||[]],[...q,...s.plugins||[]])}}));s.type==="query"&&(p[w]=(u,n)=>{let{skip:t}=n||{},{query:i,error:S,isError:m,isLoading:e,isSuccess:F,reFetch:A,data:g}=y();return k(()=>{t||i(u)},[JSON.stringify(u||{})]),{error:S,isError:m,isLoading:e,isSuccess:F,data:g,reFetch:A}}),s.type==="mutation"&&(p[w]=()=>{let{query:u,...n}=y();return[u,n]})}return p}export{P as createApi};
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zustic",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A fast, minimal state management solution for React ecosystems. Works seamlessly with React, Next.js, and React Native, offering predictable state updates with a tiny footprint.",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"module": "dist/index.mjs",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
5
|
"scripts": {
|
|
9
|
-
"build": "tsup
|
|
10
|
-
"start:cjs": "node dist/cjs/index.js",
|
|
11
|
-
"start:esm": "node dist/esm/index.js",
|
|
12
|
-
"start": "ts-node src/index.ts",
|
|
6
|
+
"build": "tsup",
|
|
13
7
|
"test": "npm run build && npm link"
|
|
14
8
|
},
|
|
15
9
|
"exports": {
|
|
16
10
|
".": {
|
|
17
|
-
"
|
|
18
|
-
"import": "./dist/index.mjs"
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./query": {
|
|
16
|
+
"types": "./dist/query/index.d.ts",
|
|
17
|
+
"import": "./dist/query/index.mjs",
|
|
18
|
+
"require": "./dist/query/index.js"
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"directories": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"nextjs",
|
|
39
39
|
"state"
|
|
40
40
|
],
|
|
41
|
-
"homepage": "https://github.
|
|
41
|
+
"homepage": "https://zustic.github.io",
|
|
42
42
|
"files": [
|
|
43
43
|
"dist/**/*",
|
|
44
44
|
"README.md"
|