create-aziz-app 3.1.1 → 3.1.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 +658 -207
- package/bin/create-aziz-app.js +302 -351
- package/package.json +1 -1
- package/template/README.md +14 -279
- package/template/_framework/api.js +219 -219
- package/template/_framework/boot.js +33 -33
- package/template/_framework/hooks.js +367 -291
- package/template/_framework/next-response.js +128 -128
- package/template/_framework/route-match.js +145 -145
- package/template/_framework/router.js +465 -259
- package/template/_framework/runtime.js +264 -264
- package/template/app/layout.js +3 -5
- package/template/app/page.js +9 -32
- package/template/docs/01-getting-started.md +151 -151
- package/template/docs/02-project-structure.md +109 -109
- package/template/docs/03-pages-and-layouts.md +140 -140
- package/template/docs/04-routing.md +120 -120
- package/template/docs/05-hooks.md +169 -169
- package/template/docs/06-api-routes.md +210 -210
- package/template/docs/07-api-client.md +151 -151
- package/template/docs/08-styling.md +94 -94
- package/template/docs/09-imports-and-modules.md +97 -97
- package/template/docs/10-database-and-models.md +154 -154
- package/template/docs/11-authentication.md +171 -171
- package/template/docs/12-production-and-deployment.md +121 -121
- package/template/docs/13-internals.md +179 -179
- package/template/docs/README.md +67 -67
- package/template/index.html +20 -20
- package/template/package.json +16 -16
- package/template/scripts/dev-server.js +493 -381
- package/template/scripts/lib/api-router.js +525 -525
- package/template/scripts/lib/js-transform.js +213 -141
- package/template/scripts/lib/module-resolver.js +132 -132
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
# 05 · Hooks
|
|
2
|
-
|
|
3
|
-
Aziz.js implements the React hooks API. **No imports are needed** — every hook is a global.
|
|
4
|
-
|
|
5
|
-
```js
|
|
6
|
-
const [count, setCount] = useState(0); // just works
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
## `useState`
|
|
10
|
-
|
|
11
|
-
```js
|
|
12
|
-
const [count, setCount] = useState(0);
|
|
13
|
-
|
|
14
|
-
// Functional update (uses the latest value):
|
|
15
|
-
setCount(c => c + 1);
|
|
16
|
-
|
|
17
|
-
// Re-render only happens if the value actually changed:
|
|
18
|
-
setCount(0); // if it's already 0, nothing happens
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Each component instance gets **its own** state, keyed by its position in the tree. Two `<Counter />` siblings never share state, even without keys (keys make it explicit and stable — always pass `key` in lists).
|
|
22
|
-
|
|
23
|
-
## `useReducer`
|
|
24
|
-
|
|
25
|
-
```js
|
|
26
|
-
function reducer(state, action) {
|
|
27
|
-
switch (action.type) {
|
|
28
|
-
case 'inc': return { count: state.count + 1 };
|
|
29
|
-
case 'reset': return { count: 0 };
|
|
30
|
-
default: return state;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const [state, dispatch] = useReducer(reducer, { count: 0 });
|
|
35
|
-
|
|
36
|
-
dispatch({ type: 'inc' });
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Signature matches React: `useReducer(reducer, initialState, init?)`.
|
|
40
|
-
|
|
41
|
-
## `useEffect`
|
|
42
|
-
|
|
43
|
-
Run side effects after render. Always return a **cleanup** function if you subscribe/touch timers:
|
|
44
|
-
|
|
45
|
-
```js
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
const id = setInterval(tick, 1000);
|
|
48
|
-
return () => clearInterval(id); // cleanup on unmount / dep change
|
|
49
|
-
}, []); // [] = run once
|
|
50
|
-
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
document.title = name;
|
|
53
|
-
}, [name]); // rerun when name changes
|
|
54
|
-
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
// no dep array → runs after EVERY render
|
|
57
|
-
});
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Rules:
|
|
61
|
-
|
|
62
|
-
- The callback runs **asynchronously** after the DOM update (a microtask), not during render.
|
|
63
|
-
- The returned cleanup runs when deps change or the component unmounts.
|
|
64
|
-
- **On route change, all effects are cleaned up** — navigating away from a page with a `setInterval` won't leak the timer.
|
|
65
|
-
|
|
66
|
-
## `useMemo` / `useCallback`
|
|
67
|
-
|
|
68
|
-
```js
|
|
69
|
-
const expensive = useMemo(() => compute(a, b), [a, b]);
|
|
70
|
-
const onClick = useCallback(() => doThing(id), [id]);
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Memoize only when the work is actually expensive — otherwise it's overhead.
|
|
74
|
-
|
|
75
|
-
## `useRef`
|
|
76
|
-
|
|
77
|
-
Mutable box that survives re-renders without causing them:
|
|
78
|
-
|
|
79
|
-
```js
|
|
80
|
-
const inputRef = useRef(null);
|
|
81
|
-
|
|
82
|
-
useEffect(() => { inputRef.current?.focus(); }, []);
|
|
83
|
-
|
|
84
|
-
return <input ref={inputRef} />;
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
`ref` accepts a **function** (`ref={el => (node = el)}`) or an **object** (`ref={r}`); both receive the real DOM node.
|
|
88
|
-
|
|
89
|
-
## Context
|
|
90
|
-
|
|
91
|
-
Share a value through the tree without prop drilling:
|
|
92
|
-
|
|
93
|
-
```js
|
|
94
|
-
const ThemeContext = createContext('light');
|
|
95
|
-
|
|
96
|
-
function App() {
|
|
97
|
-
return (
|
|
98
|
-
<ThemeContext.Provider value="dark">
|
|
99
|
-
<Toolbar />
|
|
100
|
-
</ThemeContext.Provider>
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function ThemeButton() {
|
|
105
|
-
const theme = useContext(ThemeContext); // "dark"
|
|
106
|
-
return <span>{theme}</span>;
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
- `useContext(SomeContext)` returns the nearest provider's value, or the **default** if no provider is above.
|
|
111
|
-
- **Nested providers**: the innermost wins for its subtree.
|
|
112
|
-
- Providers can be nested and combined with arbitrary wrapping elements — context is resolved during a top-down materialization pass, so a provider's value is visible to everything it renders.
|
|
113
|
-
|
|
114
|
-
## `useLocalStorage`
|
|
115
|
-
|
|
116
|
-
State that survives a refresh and syncs across tabs:
|
|
117
|
-
|
|
118
|
-
```js
|
|
119
|
-
const [name, setName] = useLocalStorage('name', '');
|
|
120
|
-
|
|
121
|
-
setName('Aziz'); // also written to localStorage
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
A `storage` event listener keeps other open tabs in sync.
|
|
125
|
-
|
|
126
|
-
## `useFetch` / `useApi`
|
|
127
|
-
|
|
128
|
-
Declarative data fetching with built-in loading/error state, abort-on-change, and a manual `refetch`:
|
|
129
|
-
|
|
130
|
-
```js
|
|
131
|
-
const { data, loading, error, refetch } = useFetch('/api/users');
|
|
132
|
-
|
|
133
|
-
if (loading) return <p>Loading…</p>;
|
|
134
|
-
if (error) return <p>Error: {error}</p>;
|
|
135
|
-
return <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
|
|
136
|
-
|
|
137
|
-
refetch(); // re-run the request
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
- `data` is parsed from JSON when the response is JSON (otherwise text).
|
|
141
|
-
- In-flight requests are **aborted** if the URL changes or the component unmounts.
|
|
142
|
-
- `useApi` is an alias of `useFetch`.
|
|
143
|
-
|
|
144
|
-
For imperative calls (POST, retries, custom headers) use the [API Client](./07-api-client.md) instead.
|
|
145
|
-
|
|
146
|
-
## Router hooks
|
|
147
|
-
|
|
148
|
-
```js
|
|
149
|
-
const { pathname, push, replace, back, refresh, params } = useRouter();
|
|
150
|
-
const { slug } = useParams();
|
|
151
|
-
const q = useSearchParams().get('q');
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
See [Routing](./04-routing.md).
|
|
155
|
-
|
|
156
|
-
## Global registry
|
|
157
|
-
|
|
158
|
-
Available in every page/component without importing:
|
|
159
|
-
|
|
160
|
-
```
|
|
161
|
-
useState useEffect useMemo useCallback useRef useReducer
|
|
162
|
-
useContext createContext useLocalStorage useFetch useApi
|
|
163
|
-
useRouter useParams useSearchParams
|
|
164
|
-
navigate Link h Fragment api
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
## Continue
|
|
168
|
-
|
|
169
|
-
→ [API Routes](./06-api-routes.md)
|
|
1
|
+
# 05 · Hooks
|
|
2
|
+
|
|
3
|
+
Aziz.js implements the React hooks API. **No imports are needed** — every hook is a global.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
const [count, setCount] = useState(0); // just works
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## `useState`
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
const [count, setCount] = useState(0);
|
|
13
|
+
|
|
14
|
+
// Functional update (uses the latest value):
|
|
15
|
+
setCount(c => c + 1);
|
|
16
|
+
|
|
17
|
+
// Re-render only happens if the value actually changed:
|
|
18
|
+
setCount(0); // if it's already 0, nothing happens
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Each component instance gets **its own** state, keyed by its position in the tree. Two `<Counter />` siblings never share state, even without keys (keys make it explicit and stable — always pass `key` in lists).
|
|
22
|
+
|
|
23
|
+
## `useReducer`
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
function reducer(state, action) {
|
|
27
|
+
switch (action.type) {
|
|
28
|
+
case 'inc': return { count: state.count + 1 };
|
|
29
|
+
case 'reset': return { count: 0 };
|
|
30
|
+
default: return state;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const [state, dispatch] = useReducer(reducer, { count: 0 });
|
|
35
|
+
|
|
36
|
+
dispatch({ type: 'inc' });
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Signature matches React: `useReducer(reducer, initialState, init?)`.
|
|
40
|
+
|
|
41
|
+
## `useEffect`
|
|
42
|
+
|
|
43
|
+
Run side effects after render. Always return a **cleanup** function if you subscribe/touch timers:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const id = setInterval(tick, 1000);
|
|
48
|
+
return () => clearInterval(id); // cleanup on unmount / dep change
|
|
49
|
+
}, []); // [] = run once
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
document.title = name;
|
|
53
|
+
}, [name]); // rerun when name changes
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
// no dep array → runs after EVERY render
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Rules:
|
|
61
|
+
|
|
62
|
+
- The callback runs **asynchronously** after the DOM update (a microtask), not during render.
|
|
63
|
+
- The returned cleanup runs when deps change or the component unmounts.
|
|
64
|
+
- **On route change, all effects are cleaned up** — navigating away from a page with a `setInterval` won't leak the timer.
|
|
65
|
+
|
|
66
|
+
## `useMemo` / `useCallback`
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
const expensive = useMemo(() => compute(a, b), [a, b]);
|
|
70
|
+
const onClick = useCallback(() => doThing(id), [id]);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Memoize only when the work is actually expensive — otherwise it's overhead.
|
|
74
|
+
|
|
75
|
+
## `useRef`
|
|
76
|
+
|
|
77
|
+
Mutable box that survives re-renders without causing them:
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
const inputRef = useRef(null);
|
|
81
|
+
|
|
82
|
+
useEffect(() => { inputRef.current?.focus(); }, []);
|
|
83
|
+
|
|
84
|
+
return <input ref={inputRef} />;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`ref` accepts a **function** (`ref={el => (node = el)}`) or an **object** (`ref={r}`); both receive the real DOM node.
|
|
88
|
+
|
|
89
|
+
## Context
|
|
90
|
+
|
|
91
|
+
Share a value through the tree without prop drilling:
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
const ThemeContext = createContext('light');
|
|
95
|
+
|
|
96
|
+
function App() {
|
|
97
|
+
return (
|
|
98
|
+
<ThemeContext.Provider value="dark">
|
|
99
|
+
<Toolbar />
|
|
100
|
+
</ThemeContext.Provider>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function ThemeButton() {
|
|
105
|
+
const theme = useContext(ThemeContext); // "dark"
|
|
106
|
+
return <span>{theme}</span>;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- `useContext(SomeContext)` returns the nearest provider's value, or the **default** if no provider is above.
|
|
111
|
+
- **Nested providers**: the innermost wins for its subtree.
|
|
112
|
+
- Providers can be nested and combined with arbitrary wrapping elements — context is resolved during a top-down materialization pass, so a provider's value is visible to everything it renders.
|
|
113
|
+
|
|
114
|
+
## `useLocalStorage`
|
|
115
|
+
|
|
116
|
+
State that survives a refresh and syncs across tabs:
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
const [name, setName] = useLocalStorage('name', '');
|
|
120
|
+
|
|
121
|
+
setName('Aziz'); // also written to localStorage
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
A `storage` event listener keeps other open tabs in sync.
|
|
125
|
+
|
|
126
|
+
## `useFetch` / `useApi`
|
|
127
|
+
|
|
128
|
+
Declarative data fetching with built-in loading/error state, abort-on-change, and a manual `refetch`:
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
const { data, loading, error, refetch } = useFetch('/api/users');
|
|
132
|
+
|
|
133
|
+
if (loading) return <p>Loading…</p>;
|
|
134
|
+
if (error) return <p>Error: {error}</p>;
|
|
135
|
+
return <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
|
|
136
|
+
|
|
137
|
+
refetch(); // re-run the request
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
- `data` is parsed from JSON when the response is JSON (otherwise text).
|
|
141
|
+
- In-flight requests are **aborted** if the URL changes or the component unmounts.
|
|
142
|
+
- `useApi` is an alias of `useFetch`.
|
|
143
|
+
|
|
144
|
+
For imperative calls (POST, retries, custom headers) use the [API Client](./07-api-client.md) instead.
|
|
145
|
+
|
|
146
|
+
## Router hooks
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
const { pathname, push, replace, back, refresh, params } = useRouter();
|
|
150
|
+
const { slug } = useParams();
|
|
151
|
+
const q = useSearchParams().get('q');
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
See [Routing](./04-routing.md).
|
|
155
|
+
|
|
156
|
+
## Global registry
|
|
157
|
+
|
|
158
|
+
Available in every page/component without importing:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
useState useEffect useMemo useCallback useRef useReducer
|
|
162
|
+
useContext createContext useLocalStorage useFetch useApi
|
|
163
|
+
useRouter useParams useSearchParams
|
|
164
|
+
navigate Link h Fragment api
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Continue
|
|
168
|
+
|
|
169
|
+
→ [API Routes](./06-api-routes.md)
|