hank-zilla 1.2.2 â 3.0.1
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/LICENSE +21 -21
- package/README.md +116 -209
- package/dist/LICENSE +21 -21
- package/dist/README.md +116 -209
- package/dist/useAppState/appState.d.ts +1 -1
- package/dist/useAppState/appState.js +1 -1
- package/package.json +70 -70
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 phamdung2209
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 phamdung2209
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,209 +1,116 @@
|
|
|
1
|
-
# ðĶ Hank-Zilla
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[](https://badge.fury.io/js/hank-zilla)
|
|
6
|
-
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[](https://www.typescriptlang.org/)
|
|
8
|
-
|
|
9
|
-
##
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
function
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
### Auto-cleanup with `removeOnUnmount`
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
function TemporaryComponent() {
|
|
122
|
-
// This state will be deleted when component unmounts
|
|
123
|
-
const [data, setData] = useAppState('tempData', [], true)
|
|
124
|
-
|
|
125
|
-
return <div>Temporary data: {data.length} items</div>
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### TypeScript Support
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
interface CartItem {
|
|
133
|
-
id: string
|
|
134
|
-
name: string
|
|
135
|
-
price: number
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Type inference
|
|
139
|
-
const [cart, setCart] = useAppState<CartItem[]>('cart', [])
|
|
140
|
-
|
|
141
|
-
// Add item with type safety
|
|
142
|
-
const addItem = (item: CartItem) => {
|
|
143
|
-
setCart((prev) => [...prev, item])
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Performance: When to use `getAppState`
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
// â
Good: Use useAppState for UI components
|
|
151
|
-
function Counter() {
|
|
152
|
-
const [count, setCount] = useAppState('count', 0)
|
|
153
|
-
return <div>Count: {count}</div> // Re-renders when count changes
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// â
Good: Use getAppState for utilities/callbacks
|
|
157
|
-
function logCurrentState() {
|
|
158
|
-
const count = getAppState('count')
|
|
159
|
-
console.log('Current count:', count) // No re-renders
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## ð Comparison
|
|
164
|
-
|
|
165
|
-
| Feature | Hank-Zilla | Context API | Redux | Zustand |
|
|
166
|
-
| ----------------- | ----------- | ----------------- | ------------------ | ----------- |
|
|
167
|
-
| **Setup** | â None | â
Provider | â
Store + Actions | â
Store |
|
|
168
|
-
| **Bundle Size** | ðĒ ~1.3KB | ðĒ Built-in | ðī ~45KB | ðĄ ~8KB |
|
|
169
|
-
| **Global Access** | â
Anywhere | â Provider scope | â
Anywhere | â
Anywhere |
|
|
170
|
-
| **TypeScript** | ðĒ Full | ðĄ Manual | ðĒ Full | ðĒ Full |
|
|
171
|
-
|
|
172
|
-
## ð§ Migration
|
|
173
|
-
|
|
174
|
-
### From `useState` to `useAppState`
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
// Before: Local state
|
|
178
|
-
const [count, setCount] = useState(0)
|
|
179
|
-
|
|
180
|
-
// After: Global state
|
|
181
|
-
const count = useAppState('count', 0)
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### From Context API
|
|
185
|
-
|
|
186
|
-
```typescript
|
|
187
|
-
// Before: Complex setup
|
|
188
|
-
const UserContext = createContext()
|
|
189
|
-
const { user, setUser } = useContext(UserContext)
|
|
190
|
-
|
|
191
|
-
// After: Direct usage
|
|
192
|
-
const user = useAppState('user', null)
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
## ðĪ Contributing
|
|
196
|
-
|
|
197
|
-
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
198
|
-
|
|
199
|
-
## ð License
|
|
200
|
-
|
|
201
|
-
MIT License - see the [LICENSE](LICENSE) file for details.
|
|
202
|
-
|
|
203
|
-
## ð Acknowledgments
|
|
204
|
-
|
|
205
|
-
Built with âĪïļ by [phamdung2209](https://github.com/phamdung2209) âĒ Special thanks to the React team for `useSyncExternalStore`
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
Made with ðĶ by the Hank-Zilla team
|
|
1
|
+
# ðĶ Hank-Zilla
|
|
2
|
+
|
|
3
|
+
Global React state with the ergonomics of `useState` â no Provider, no boilerplate, no dependencies.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/hank-zilla)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **No Provider** â read and write the same state from any component
|
|
12
|
+
- **Familiar** â `useAppState` reads like `useState`, but global
|
|
13
|
+
- **Tiny** â zero dependencies, ~0.7 KB gzipped
|
|
14
|
+
- **Correct** â built on `useSyncExternalStore`, concurrent-safe
|
|
15
|
+
- **Typed** â full TypeScript inference
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install hank-zilla
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
`useAppState` returns the **value** and subscribes to it. Write with `setAppState` from anywhere â no props, no context.
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { useAppState, setAppState } from 'hank-zilla'
|
|
29
|
+
|
|
30
|
+
function Counter() {
|
|
31
|
+
const count = useAppState('count', 0)
|
|
32
|
+
return <button onClick={() => setAppState('count', (n) => n + 1)}>{count}</button>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Another component, same state â nothing passed down
|
|
36
|
+
function Readout() {
|
|
37
|
+
const count = useAppState('count')
|
|
38
|
+
return <p>Count is {count}</p>
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## API
|
|
43
|
+
|
|
44
|
+
### `useAppState<T>(key, defaultValue?, removeOnUnmount?, silent?) â T`
|
|
45
|
+
|
|
46
|
+
Subscribe to a key and get its current value. Re-renders only when that key changes.
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
const count = useAppState('count', 0)
|
|
50
|
+
const user = useAppState<User>('user', null)
|
|
51
|
+
const temp = useAppState('draft', '', true) // removed from the store on unmount
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### `setAppState(key, value | updater, silent?)`
|
|
55
|
+
|
|
56
|
+
Write a key from anywhere. A plain value **replaces**; a function is an **updater** `(prev) => next`.
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
setAppState('count', 42) // replace
|
|
60
|
+
setAppState('count', (n) => n + 1) // updater
|
|
61
|
+
setAppState('user', { name: 'Jane' }) // replaces the whole value
|
|
62
|
+
setAppState('user', (u) => ({ ...u, name: 'Jane' })) // merge â via updater
|
|
63
|
+
setAppState('items', (list) => [...list, item]) // append â via updater
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Each key is independent: writing `count` never touches `user`. Pass `silent` to update without notifying subscribers.
|
|
67
|
+
|
|
68
|
+
### `getAppState(key?)`
|
|
69
|
+
|
|
70
|
+
Read without subscribing â no re-render. Handy in callbacks and utilities.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
getAppState('count') // one key
|
|
74
|
+
getAppState() // the whole store
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `deleteAppState(key)`
|
|
78
|
+
|
|
79
|
+
Remove a key and re-render its subscribers (they fall back to their default).
|
|
80
|
+
|
|
81
|
+
### `$getAppState()` â console helper
|
|
82
|
+
|
|
83
|
+
Exposed on `globalThis` for debugging in the browser console.
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
$getAppState() // the whole store
|
|
87
|
+
$getAppState('count') // one key
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Comparison
|
|
91
|
+
|
|
92
|
+
| | Hank-Zilla | Context API | Redux | Zustand |
|
|
93
|
+
| --- | --- | --- | --- | --- |
|
|
94
|
+
| Provider needed | No | Yes | Yes | No |
|
|
95
|
+
| Boilerplate | None | Some | High | Low |
|
|
96
|
+
| Global access | Yes | Provider scope | Yes | Yes |
|
|
97
|
+
| Bundle (gzip) | ~0.7 KB | built-in | large | ~1 KB |
|
|
98
|
+
| TypeScript | Full | Manual | Full | Full |
|
|
99
|
+
|
|
100
|
+
## Migration
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
// Local state
|
|
104
|
+
const [count, setCount] = useState(0)
|
|
105
|
+
setCount((n) => n + 1)
|
|
106
|
+
|
|
107
|
+
// Global state
|
|
108
|
+
const count = useAppState('count', 0)
|
|
109
|
+
setAppState('count', (n) => n + 1)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT â see [LICENSE](LICENSE).
|
|
115
|
+
|
|
116
|
+
Built by [phamdung2209](https://github.com/phamdung2209) ðĶ
|
package/dist/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 phamdung2209
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 phamdung2209
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/README.md
CHANGED
|
@@ -1,209 +1,116 @@
|
|
|
1
|
-
# ðĶ Hank-Zilla
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[](https://badge.fury.io/js/hank-zilla)
|
|
6
|
-
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[](https://www.typescriptlang.org/)
|
|
8
|
-
|
|
9
|
-
##
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
function
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
### Auto-cleanup with `removeOnUnmount`
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
function TemporaryComponent() {
|
|
122
|
-
// This state will be deleted when component unmounts
|
|
123
|
-
const [data, setData] = useAppState('tempData', [], true)
|
|
124
|
-
|
|
125
|
-
return <div>Temporary data: {data.length} items</div>
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### TypeScript Support
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
interface CartItem {
|
|
133
|
-
id: string
|
|
134
|
-
name: string
|
|
135
|
-
price: number
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Type inference
|
|
139
|
-
const [cart, setCart] = useAppState<CartItem[]>('cart', [])
|
|
140
|
-
|
|
141
|
-
// Add item with type safety
|
|
142
|
-
const addItem = (item: CartItem) => {
|
|
143
|
-
setCart((prev) => [...prev, item])
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Performance: When to use `getAppState`
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
// â
Good: Use useAppState for UI components
|
|
151
|
-
function Counter() {
|
|
152
|
-
const [count, setCount] = useAppState('count', 0)
|
|
153
|
-
return <div>Count: {count}</div> // Re-renders when count changes
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// â
Good: Use getAppState for utilities/callbacks
|
|
157
|
-
function logCurrentState() {
|
|
158
|
-
const count = getAppState('count')
|
|
159
|
-
console.log('Current count:', count) // No re-renders
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## ð Comparison
|
|
164
|
-
|
|
165
|
-
| Feature | Hank-Zilla | Context API | Redux | Zustand |
|
|
166
|
-
| ----------------- | ----------- | ----------------- | ------------------ | ----------- |
|
|
167
|
-
| **Setup** | â None | â
Provider | â
Store + Actions | â
Store |
|
|
168
|
-
| **Bundle Size** | ðĒ ~1.3KB | ðĒ Built-in | ðī ~45KB | ðĄ ~8KB |
|
|
169
|
-
| **Global Access** | â
Anywhere | â Provider scope | â
Anywhere | â
Anywhere |
|
|
170
|
-
| **TypeScript** | ðĒ Full | ðĄ Manual | ðĒ Full | ðĒ Full |
|
|
171
|
-
|
|
172
|
-
## ð§ Migration
|
|
173
|
-
|
|
174
|
-
### From `useState` to `useAppState`
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
// Before: Local state
|
|
178
|
-
const [count, setCount] = useState(0)
|
|
179
|
-
|
|
180
|
-
// After: Global state
|
|
181
|
-
const count = useAppState('count', 0)
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### From Context API
|
|
185
|
-
|
|
186
|
-
```typescript
|
|
187
|
-
// Before: Complex setup
|
|
188
|
-
const UserContext = createContext()
|
|
189
|
-
const { user, setUser } = useContext(UserContext)
|
|
190
|
-
|
|
191
|
-
// After: Direct usage
|
|
192
|
-
const user = useAppState('user', null)
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
## ðĪ Contributing
|
|
196
|
-
|
|
197
|
-
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
198
|
-
|
|
199
|
-
## ð License
|
|
200
|
-
|
|
201
|
-
MIT License - see the [LICENSE](LICENSE) file for details.
|
|
202
|
-
|
|
203
|
-
## ð Acknowledgments
|
|
204
|
-
|
|
205
|
-
Built with âĪïļ by [phamdung2209](https://github.com/phamdung2209) âĒ Special thanks to the React team for `useSyncExternalStore`
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
Made with ðĶ by the Hank-Zilla team
|
|
1
|
+
# ðĶ Hank-Zilla
|
|
2
|
+
|
|
3
|
+
Global React state with the ergonomics of `useState` â no Provider, no boilerplate, no dependencies.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/hank-zilla)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **No Provider** â read and write the same state from any component
|
|
12
|
+
- **Familiar** â `useAppState` reads like `useState`, but global
|
|
13
|
+
- **Tiny** â zero dependencies, ~0.7 KB gzipped
|
|
14
|
+
- **Correct** â built on `useSyncExternalStore`, concurrent-safe
|
|
15
|
+
- **Typed** â full TypeScript inference
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install hank-zilla
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
`useAppState` returns the **value** and subscribes to it. Write with `setAppState` from anywhere â no props, no context.
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { useAppState, setAppState } from 'hank-zilla'
|
|
29
|
+
|
|
30
|
+
function Counter() {
|
|
31
|
+
const count = useAppState('count', 0)
|
|
32
|
+
return <button onClick={() => setAppState('count', (n) => n + 1)}>{count}</button>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Another component, same state â nothing passed down
|
|
36
|
+
function Readout() {
|
|
37
|
+
const count = useAppState('count')
|
|
38
|
+
return <p>Count is {count}</p>
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## API
|
|
43
|
+
|
|
44
|
+
### `useAppState<T>(key, defaultValue?, removeOnUnmount?, silent?) â T`
|
|
45
|
+
|
|
46
|
+
Subscribe to a key and get its current value. Re-renders only when that key changes.
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
const count = useAppState('count', 0)
|
|
50
|
+
const user = useAppState<User>('user', null)
|
|
51
|
+
const temp = useAppState('draft', '', true) // removed from the store on unmount
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### `setAppState(key, value | updater, silent?)`
|
|
55
|
+
|
|
56
|
+
Write a key from anywhere. A plain value **replaces**; a function is an **updater** `(prev) => next`.
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
setAppState('count', 42) // replace
|
|
60
|
+
setAppState('count', (n) => n + 1) // updater
|
|
61
|
+
setAppState('user', { name: 'Jane' }) // replaces the whole value
|
|
62
|
+
setAppState('user', (u) => ({ ...u, name: 'Jane' })) // merge â via updater
|
|
63
|
+
setAppState('items', (list) => [...list, item]) // append â via updater
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Each key is independent: writing `count` never touches `user`. Pass `silent` to update without notifying subscribers.
|
|
67
|
+
|
|
68
|
+
### `getAppState(key?)`
|
|
69
|
+
|
|
70
|
+
Read without subscribing â no re-render. Handy in callbacks and utilities.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
getAppState('count') // one key
|
|
74
|
+
getAppState() // the whole store
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `deleteAppState(key)`
|
|
78
|
+
|
|
79
|
+
Remove a key and re-render its subscribers (they fall back to their default).
|
|
80
|
+
|
|
81
|
+
### `$getAppState()` â console helper
|
|
82
|
+
|
|
83
|
+
Exposed on `globalThis` for debugging in the browser console.
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
$getAppState() // the whole store
|
|
87
|
+
$getAppState('count') // one key
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Comparison
|
|
91
|
+
|
|
92
|
+
| | Hank-Zilla | Context API | Redux | Zustand |
|
|
93
|
+
| --- | --- | --- | --- | --- |
|
|
94
|
+
| Provider needed | No | Yes | Yes | No |
|
|
95
|
+
| Boilerplate | None | Some | High | Low |
|
|
96
|
+
| Global access | Yes | Provider scope | Yes | Yes |
|
|
97
|
+
| Bundle (gzip) | ~0.7 KB | built-in | large | ~1 KB |
|
|
98
|
+
| TypeScript | Full | Manual | Full | Full |
|
|
99
|
+
|
|
100
|
+
## Migration
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
// Local state
|
|
104
|
+
const [count, setCount] = useState(0)
|
|
105
|
+
setCount((n) => n + 1)
|
|
106
|
+
|
|
107
|
+
// Global state
|
|
108
|
+
const count = useAppState('count', 0)
|
|
109
|
+
setAppState('count', (n) => n + 1)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT â see [LICENSE](LICENSE).
|
|
115
|
+
|
|
116
|
+
Built by [phamdung2209](https://github.com/phamdung2209) ðĶ
|
|
@@ -2,7 +2,7 @@ declare const store: {
|
|
|
2
2
|
state: Record<string, any>;
|
|
3
3
|
getState: () => Record<string, any>;
|
|
4
4
|
subscribe: (callback: () => void) => () => boolean;
|
|
5
|
-
setState: (
|
|
5
|
+
setState: (changes: Record<string, any>, silent?: boolean) => void;
|
|
6
6
|
};
|
|
7
7
|
export declare const useAppState: <T>(key: string, defaultValue?: T, removeOnUnmount?: boolean, silent?: boolean) => T;
|
|
8
8
|
export declare const setAppState: (key: string, newValue: any, silent?: boolean) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useEffect,useSyncExternalStore}from"react";import init$ from"./init$";const listeners=new Set,store={state:{},getState:()=>store.state,subscribe:t=>(listeners.add(t),()=>listeners.delete(t)),setState:(t,e)=>{
|
|
1
|
+
import{useEffect,useSyncExternalStore}from"react";import init$ from"./init$";const listeners=new Set,store={state:{},getState:()=>store.state,subscribe:t=>(listeners.add(t),()=>listeners.delete(t)),setState:(t,e)=>{const s={...store.state};for(const[e,o]of Object.entries(t))s[e]="function"==typeof o?o(store.state[e]):o;store.state=s,e||listeners.forEach(t=>t())}};export const useAppState=(t,e,s=!1,o)=>(t in store.state||void 0===e||store.setState({[t]:e},o),useEffect(()=>()=>{s&&deleteAppState(t)},[t,s]),useSyncExternalStore(store.subscribe,()=>store.state[t]??e,()=>e));export const setAppState=(t,e,s)=>{store.setState({[t]:e},s)};export const getAppState=t=>void 0===t?store.getState():store.getState()[t];export const deleteAppState=t=>{t in store.state&&(delete store.state[t],listeners.forEach(t=>t()))};init$({getAppState:getAppState});export default store;
|
package/package.json
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "hank-zilla",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A lightweight React state management library with modular architecture",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"module": "dist/index.js",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
|
-
"repository": {
|
|
9
|
-
"url": "https://github.com/phamdung2209/hank_zilla.git",
|
|
10
|
-
"type": "git"
|
|
11
|
-
},
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/phamdung2209/hank_zilla/issues"
|
|
14
|
-
},
|
|
15
|
-
"exports": {
|
|
16
|
-
".": {
|
|
17
|
-
"import": "./dist/index.js",
|
|
18
|
-
"require": "./dist/index.js",
|
|
19
|
-
"types": "./dist/index.d.ts"
|
|
20
|
-
},
|
|
21
|
-
"./useAppState": {
|
|
22
|
-
"import": "./dist/useAppState/index.js",
|
|
23
|
-
"require": "./dist/useAppState/index.js",
|
|
24
|
-
"types": "./dist/useAppState/index.d.ts"
|
|
25
|
-
},
|
|
26
|
-
"./package.json": "./package.json"
|
|
27
|
-
},
|
|
28
|
-
"files": [
|
|
29
|
-
"dist",
|
|
30
|
-
"README.md",
|
|
31
|
-
"LICENSE"
|
|
32
|
-
],
|
|
33
|
-
"scripts": {
|
|
34
|
-
"build": "npm run clean && tsc && npm run minify && npm run copy-files",
|
|
35
|
-
"minify": "npm run minify-index && npm run minify-useappstate",
|
|
36
|
-
"minify-index": "terser dist/index.js -o dist/index.js -c -m",
|
|
37
|
-
"minify-useappstate": "terser dist/useAppState/index.js -o dist/useAppState/index.js -c -m && terser dist/useAppState/appState.js -o dist/useAppState/appState.js -c -m",
|
|
38
|
-
"copy-files": "npm run copy-readme && npm run copy-license",
|
|
39
|
-
"copy-readme": "cp README.md dist/ || copy README.md dist\\",
|
|
40
|
-
"copy-license": "cp LICENSE dist/ || copy LICENSE dist\\ || echo 'LICENSE not found'",
|
|
41
|
-
"dev": "tsc --watch",
|
|
42
|
-
"clean": "rimraf dist",
|
|
43
|
-
"prepublishOnly": "npm run build",
|
|
44
|
-
"postbuild": "ls -la dist || dir dist",
|
|
45
|
-
"release:patch": "npm version patch && npm publish && git push origin --tags",
|
|
46
|
-
"release:minor": "npm version minor && npm publish && git push origin --tags",
|
|
47
|
-
"release:major": "npm version major && npm publish && git push origin --tags",
|
|
48
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
49
|
-
},
|
|
50
|
-
"keywords": [
|
|
51
|
-
"react",
|
|
52
|
-
"state-management",
|
|
53
|
-
"hook",
|
|
54
|
-
"useState",
|
|
55
|
-
"global-state",
|
|
56
|
-
"modular",
|
|
57
|
-
"tree-shaking"
|
|
58
|
-
],
|
|
59
|
-
"author": "phamdung2209",
|
|
60
|
-
"license": "MIT",
|
|
61
|
-
"peerDependencies": {
|
|
62
|
-
"react": ">=16.8.0"
|
|
63
|
-
},
|
|
64
|
-
"devDependencies": {
|
|
65
|
-
"@types/react": "^19.1.8",
|
|
66
|
-
"typescript": "^5.8.3",
|
|
67
|
-
"rimraf": "^6.0.1",
|
|
68
|
-
"terser": "^5.36.0"
|
|
69
|
-
}
|
|
70
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "hank-zilla",
|
|
3
|
+
"version": "3.0.1",
|
|
4
|
+
"description": "A lightweight React state management library with modular architecture",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"repository": {
|
|
9
|
+
"url": "https://github.com/phamdung2209/hank_zilla.git",
|
|
10
|
+
"type": "git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/phamdung2209/hank_zilla/issues"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"require": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./useAppState": {
|
|
22
|
+
"import": "./dist/useAppState/index.js",
|
|
23
|
+
"require": "./dist/useAppState/index.js",
|
|
24
|
+
"types": "./dist/useAppState/index.d.ts"
|
|
25
|
+
},
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "npm run clean && tsc && npm run minify && npm run copy-files",
|
|
35
|
+
"minify": "npm run minify-index && npm run minify-useappstate",
|
|
36
|
+
"minify-index": "terser dist/index.js -o dist/index.js -c -m",
|
|
37
|
+
"minify-useappstate": "terser dist/useAppState/index.js -o dist/useAppState/index.js -c -m && terser dist/useAppState/appState.js -o dist/useAppState/appState.js -c -m",
|
|
38
|
+
"copy-files": "npm run copy-readme && npm run copy-license",
|
|
39
|
+
"copy-readme": "cp README.md dist/ || copy README.md dist\\",
|
|
40
|
+
"copy-license": "cp LICENSE dist/ || copy LICENSE dist\\ || echo 'LICENSE not found'",
|
|
41
|
+
"dev": "tsc --watch",
|
|
42
|
+
"clean": "rimraf dist",
|
|
43
|
+
"prepublishOnly": "npm run build",
|
|
44
|
+
"postbuild": "ls -la dist || dir dist",
|
|
45
|
+
"release:patch": "npm version patch && npm publish && git push origin --tags",
|
|
46
|
+
"release:minor": "npm version minor && npm publish && git push origin --tags",
|
|
47
|
+
"release:major": "npm version major && npm publish && git push origin --tags",
|
|
48
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
49
|
+
},
|
|
50
|
+
"keywords": [
|
|
51
|
+
"react",
|
|
52
|
+
"state-management",
|
|
53
|
+
"hook",
|
|
54
|
+
"useState",
|
|
55
|
+
"global-state",
|
|
56
|
+
"modular",
|
|
57
|
+
"tree-shaking"
|
|
58
|
+
],
|
|
59
|
+
"author": "phamdung2209",
|
|
60
|
+
"license": "MIT",
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"react": ">=16.8.0"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@types/react": "^19.1.8",
|
|
66
|
+
"typescript": "^5.8.3",
|
|
67
|
+
"rimraf": "^6.0.1",
|
|
68
|
+
"terser": "^5.36.0"
|
|
69
|
+
}
|
|
70
|
+
}
|