hank-zilla 1.2.2 â 3.0.0
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 +65 -158
- package/dist/LICENSE +21 -21
- package/dist/README.md +65 -158
- 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
1
|
# ðĶ Hank-Zilla
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Global React state with the ergonomics of `useState` â no Provider, no boilerplate, no dependencies.
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/hank-zilla)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://www.typescriptlang.org/)
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Features
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- ðĶ **TypeScript**: Full TypeScript support with type inference
|
|
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
|
|
17
16
|
|
|
18
|
-
##
|
|
17
|
+
## Install
|
|
19
18
|
|
|
20
19
|
```bash
|
|
21
20
|
npm install hank-zilla
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
##
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
import { useAppState, setAppState, getAppState } from 'hank-zilla'
|
|
28
|
-
|
|
29
|
-
// Parent Component - Set state
|
|
30
|
-
function ParentComponent() {
|
|
31
|
-
const user = useAppState('user', { name: '', email: '' })
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<div>
|
|
35
|
-
<button
|
|
36
|
-
onClick={() => setAppState('user', { name: 'John Doe', email: 'john@example.com' })}
|
|
37
|
-
>
|
|
38
|
-
Set User
|
|
39
|
-
</button>
|
|
40
|
-
<ChildComponent />
|
|
41
|
-
</div>
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Child Component - Access same state (no props needed!)
|
|
46
|
-
function ChildComponent() {
|
|
47
|
-
const user = useAppState('user')
|
|
48
|
-
|
|
49
|
-
return <div>{user ? `Welcome, ${user.name}!` : 'No user logged in'}</div>
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## ð API Reference
|
|
23
|
+
## Quick start
|
|
54
24
|
|
|
55
|
-
|
|
25
|
+
`useAppState` returns the **value** and subscribes to it. Write with `setAppState` from anywhere â no props, no context.
|
|
56
26
|
|
|
57
|
-
|
|
27
|
+
```tsx
|
|
28
|
+
import { useAppState, setAppState } from 'hank-zilla'
|
|
58
29
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// Auto-cleanup when component unmounts
|
|
64
|
-
const tempData = useAppState('tempData', null, true)
|
|
65
|
-
|
|
66
|
-
// TypeScript support
|
|
67
|
-
interface User {
|
|
68
|
-
name: string
|
|
69
|
-
email: string
|
|
30
|
+
function Counter() {
|
|
31
|
+
const count = useAppState('count', 0)
|
|
32
|
+
return <button onClick={() => setAppState('count', (n) => n + 1)}>{count}</button>
|
|
70
33
|
}
|
|
71
|
-
const user = useAppState<User>('user', null)
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### `setAppState(key, value)`
|
|
75
|
-
|
|
76
|
-
Update state from anywhere in your app - works with values or updater functions.
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
// Set value directly
|
|
80
|
-
setAppState('count', 42)
|
|
81
|
-
|
|
82
|
-
// Update with function (like useState)
|
|
83
|
-
setAppState('count', (prev) => prev + 1)
|
|
84
34
|
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
35
|
+
// Another component, same state â nothing passed down
|
|
36
|
+
function Readout() {
|
|
37
|
+
const count = useAppState('count')
|
|
38
|
+
return <p>Count is {count}</p>
|
|
39
|
+
}
|
|
90
40
|
```
|
|
91
41
|
|
|
92
|
-
|
|
42
|
+
## API
|
|
93
43
|
|
|
94
|
-
|
|
44
|
+
### `useAppState<T>(key, defaultValue?, removeOnUnmount?, silent?) â T`
|
|
95
45
|
|
|
96
|
-
|
|
97
|
-
// Get specific key
|
|
98
|
-
const currentCount = getAppState('count')
|
|
46
|
+
Subscribe to a key and get its current value. Re-renders only when that key changes.
|
|
99
47
|
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
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
|
|
104
52
|
```
|
|
105
53
|
|
|
106
|
-
###
|
|
54
|
+
### `setAppState(key, value | updater, silent?)`
|
|
107
55
|
|
|
108
|
-
|
|
56
|
+
Write a key from anywhere. A plain value **replaces**; a function is an **updater** `(prev) => next`.
|
|
109
57
|
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
|
114
64
|
```
|
|
115
65
|
|
|
116
|
-
|
|
66
|
+
Each key is independent: writing `count` never touches `user`. Pass `silent` to update without notifying subscribers.
|
|
117
67
|
|
|
118
|
-
###
|
|
68
|
+
### `getAppState(key?)`
|
|
119
69
|
|
|
120
|
-
|
|
121
|
-
function TemporaryComponent() {
|
|
122
|
-
// This state will be deleted when component unmounts
|
|
123
|
-
const [data, setData] = useAppState('tempData', [], true)
|
|
70
|
+
Read without subscribing â no re-render. Handy in callbacks and utilities.
|
|
124
71
|
|
|
125
|
-
|
|
126
|
-
|
|
72
|
+
```tsx
|
|
73
|
+
getAppState('count') // one key
|
|
74
|
+
getAppState() // the whole store
|
|
127
75
|
```
|
|
128
76
|
|
|
129
|
-
###
|
|
77
|
+
### `deleteAppState(key)`
|
|
130
78
|
|
|
131
|
-
|
|
132
|
-
interface CartItem {
|
|
133
|
-
id: string
|
|
134
|
-
name: string
|
|
135
|
-
price: number
|
|
136
|
-
}
|
|
79
|
+
Remove a key and re-render its subscribers (they fall back to their default).
|
|
137
80
|
|
|
138
|
-
|
|
139
|
-
const [cart, setCart] = useAppState<CartItem[]>('cart', [])
|
|
81
|
+
### `$getAppState()` â console helper
|
|
140
82
|
|
|
141
|
-
|
|
142
|
-
const addItem = (item: CartItem) => {
|
|
143
|
-
setCart((prev) => [...prev, item])
|
|
144
|
-
}
|
|
145
|
-
```
|
|
83
|
+
Exposed on `globalThis` for debugging in the browser console.
|
|
146
84
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
}
|
|
85
|
+
```js
|
|
86
|
+
$getAppState() // the whole store
|
|
87
|
+
$getAppState('count') // one key
|
|
161
88
|
```
|
|
162
89
|
|
|
163
|
-
##
|
|
90
|
+
## Comparison
|
|
164
91
|
|
|
165
|
-
|
|
|
166
|
-
|
|
|
167
|
-
|
|
|
168
|
-
|
|
|
169
|
-
|
|
|
170
|
-
|
|
|
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 |
|
|
171
99
|
|
|
172
|
-
##
|
|
100
|
+
## Migration
|
|
173
101
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
// Before: Local state
|
|
102
|
+
```tsx
|
|
103
|
+
// Local state
|
|
178
104
|
const [count, setCount] = useState(0)
|
|
105
|
+
setCount((n) => n + 1)
|
|
179
106
|
|
|
180
|
-
//
|
|
107
|
+
// Global state
|
|
181
108
|
const count = useAppState('count', 0)
|
|
109
|
+
setAppState('count', (n) => n + 1)
|
|
182
110
|
```
|
|
183
111
|
|
|
184
|
-
|
|
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`
|
|
112
|
+
## License
|
|
206
113
|
|
|
207
|
-
|
|
114
|
+
MIT â see [LICENSE](LICENSE).
|
|
208
115
|
|
|
209
|
-
|
|
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
1
|
# ðĶ Hank-Zilla
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Global React state with the ergonomics of `useState` â no Provider, no boilerplate, no dependencies.
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/hank-zilla)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://www.typescriptlang.org/)
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Features
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- ðĶ **TypeScript**: Full TypeScript support with type inference
|
|
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
|
|
17
16
|
|
|
18
|
-
##
|
|
17
|
+
## Install
|
|
19
18
|
|
|
20
19
|
```bash
|
|
21
20
|
npm install hank-zilla
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
##
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
import { useAppState, setAppState, getAppState } from 'hank-zilla'
|
|
28
|
-
|
|
29
|
-
// Parent Component - Set state
|
|
30
|
-
function ParentComponent() {
|
|
31
|
-
const user = useAppState('user', { name: '', email: '' })
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<div>
|
|
35
|
-
<button
|
|
36
|
-
onClick={() => setAppState('user', { name: 'John Doe', email: 'john@example.com' })}
|
|
37
|
-
>
|
|
38
|
-
Set User
|
|
39
|
-
</button>
|
|
40
|
-
<ChildComponent />
|
|
41
|
-
</div>
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Child Component - Access same state (no props needed!)
|
|
46
|
-
function ChildComponent() {
|
|
47
|
-
const user = useAppState('user')
|
|
48
|
-
|
|
49
|
-
return <div>{user ? `Welcome, ${user.name}!` : 'No user logged in'}</div>
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## ð API Reference
|
|
23
|
+
## Quick start
|
|
54
24
|
|
|
55
|
-
|
|
25
|
+
`useAppState` returns the **value** and subscribes to it. Write with `setAppState` from anywhere â no props, no context.
|
|
56
26
|
|
|
57
|
-
|
|
27
|
+
```tsx
|
|
28
|
+
import { useAppState, setAppState } from 'hank-zilla'
|
|
58
29
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// Auto-cleanup when component unmounts
|
|
64
|
-
const tempData = useAppState('tempData', null, true)
|
|
65
|
-
|
|
66
|
-
// TypeScript support
|
|
67
|
-
interface User {
|
|
68
|
-
name: string
|
|
69
|
-
email: string
|
|
30
|
+
function Counter() {
|
|
31
|
+
const count = useAppState('count', 0)
|
|
32
|
+
return <button onClick={() => setAppState('count', (n) => n + 1)}>{count}</button>
|
|
70
33
|
}
|
|
71
|
-
const user = useAppState<User>('user', null)
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### `setAppState(key, value)`
|
|
75
|
-
|
|
76
|
-
Update state from anywhere in your app - works with values or updater functions.
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
// Set value directly
|
|
80
|
-
setAppState('count', 42)
|
|
81
|
-
|
|
82
|
-
// Update with function (like useState)
|
|
83
|
-
setAppState('count', (prev) => prev + 1)
|
|
84
34
|
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
35
|
+
// Another component, same state â nothing passed down
|
|
36
|
+
function Readout() {
|
|
37
|
+
const count = useAppState('count')
|
|
38
|
+
return <p>Count is {count}</p>
|
|
39
|
+
}
|
|
90
40
|
```
|
|
91
41
|
|
|
92
|
-
|
|
42
|
+
## API
|
|
93
43
|
|
|
94
|
-
|
|
44
|
+
### `useAppState<T>(key, defaultValue?, removeOnUnmount?, silent?) â T`
|
|
95
45
|
|
|
96
|
-
|
|
97
|
-
// Get specific key
|
|
98
|
-
const currentCount = getAppState('count')
|
|
46
|
+
Subscribe to a key and get its current value. Re-renders only when that key changes.
|
|
99
47
|
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
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
|
|
104
52
|
```
|
|
105
53
|
|
|
106
|
-
###
|
|
54
|
+
### `setAppState(key, value | updater, silent?)`
|
|
107
55
|
|
|
108
|
-
|
|
56
|
+
Write a key from anywhere. A plain value **replaces**; a function is an **updater** `(prev) => next`.
|
|
109
57
|
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
|
114
64
|
```
|
|
115
65
|
|
|
116
|
-
|
|
66
|
+
Each key is independent: writing `count` never touches `user`. Pass `silent` to update without notifying subscribers.
|
|
117
67
|
|
|
118
|
-
###
|
|
68
|
+
### `getAppState(key?)`
|
|
119
69
|
|
|
120
|
-
|
|
121
|
-
function TemporaryComponent() {
|
|
122
|
-
// This state will be deleted when component unmounts
|
|
123
|
-
const [data, setData] = useAppState('tempData', [], true)
|
|
70
|
+
Read without subscribing â no re-render. Handy in callbacks and utilities.
|
|
124
71
|
|
|
125
|
-
|
|
126
|
-
|
|
72
|
+
```tsx
|
|
73
|
+
getAppState('count') // one key
|
|
74
|
+
getAppState() // the whole store
|
|
127
75
|
```
|
|
128
76
|
|
|
129
|
-
###
|
|
77
|
+
### `deleteAppState(key)`
|
|
130
78
|
|
|
131
|
-
|
|
132
|
-
interface CartItem {
|
|
133
|
-
id: string
|
|
134
|
-
name: string
|
|
135
|
-
price: number
|
|
136
|
-
}
|
|
79
|
+
Remove a key and re-render its subscribers (they fall back to their default).
|
|
137
80
|
|
|
138
|
-
|
|
139
|
-
const [cart, setCart] = useAppState<CartItem[]>('cart', [])
|
|
81
|
+
### `$getAppState()` â console helper
|
|
140
82
|
|
|
141
|
-
|
|
142
|
-
const addItem = (item: CartItem) => {
|
|
143
|
-
setCart((prev) => [...prev, item])
|
|
144
|
-
}
|
|
145
|
-
```
|
|
83
|
+
Exposed on `globalThis` for debugging in the browser console.
|
|
146
84
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
}
|
|
85
|
+
```js
|
|
86
|
+
$getAppState() // the whole store
|
|
87
|
+
$getAppState('count') // one key
|
|
161
88
|
```
|
|
162
89
|
|
|
163
|
-
##
|
|
90
|
+
## Comparison
|
|
164
91
|
|
|
165
|
-
|
|
|
166
|
-
|
|
|
167
|
-
|
|
|
168
|
-
|
|
|
169
|
-
|
|
|
170
|
-
|
|
|
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 |
|
|
171
99
|
|
|
172
|
-
##
|
|
100
|
+
## Migration
|
|
173
101
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
// Before: Local state
|
|
102
|
+
```tsx
|
|
103
|
+
// Local state
|
|
178
104
|
const [count, setCount] = useState(0)
|
|
105
|
+
setCount((n) => n + 1)
|
|
179
106
|
|
|
180
|
-
//
|
|
107
|
+
// Global state
|
|
181
108
|
const count = useAppState('count', 0)
|
|
109
|
+
setAppState('count', (n) => n + 1)
|
|
182
110
|
```
|
|
183
111
|
|
|
184
|
-
|
|
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`
|
|
112
|
+
## License
|
|
206
113
|
|
|
207
|
-
|
|
114
|
+
MIT â see [LICENSE](LICENSE).
|
|
208
115
|
|
|
209
|
-
|
|
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,useRef,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,r]of Object.entries(t))s[e]="function"==typeof r?r(store.state[e]):r;store.state=s,e||listeners.forEach(t=>t())}};export const useAppState=(t,e,s=!1,r)=>{const o=useRef(e).current;return useEffect(()=>(t in store.state||void 0===o||store.setState({[t]:o},r),()=>{s&&deleteAppState(t)}),[t,s,o,r]),useSyncExternalStore(store.subscribe,()=>store.state[t]??o,()=>o)};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.0",
|
|
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
|
+
}
|