lego-dom 0.0.5 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/deploy-docs.yml +56 -0
- package/LICENSE +21 -0
- package/README.md +298 -355
- package/docs/.vitepress/config.js +107 -0
- package/docs/.vitepress/dist/404.html +22 -0
- package/docs/.vitepress/dist/api/define.html +35 -0
- package/docs/.vitepress/dist/api/directives.html +32 -0
- package/docs/.vitepress/dist/api/globals.html +27 -0
- package/docs/.vitepress/dist/api/index.html +25 -0
- package/docs/.vitepress/dist/api/lifecycle.html +38 -0
- package/docs/.vitepress/dist/api/route.html +34 -0
- package/docs/.vitepress/dist/api/vite-plugin.html +37 -0
- package/docs/.vitepress/dist/assets/api_define.md.UA-ygUnQ.js +11 -0
- package/docs/.vitepress/dist/assets/api_define.md.UA-ygUnQ.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_directives.md.BV-D251p.js +8 -0
- package/docs/.vitepress/dist/assets/api_directives.md.BV-D251p.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_globals.md.DOjt7AV0.js +3 -0
- package/docs/.vitepress/dist/assets/api_globals.md.DOjt7AV0.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_index.md.OS6h01ct.js +1 -0
- package/docs/.vitepress/dist/assets/api_index.md.OS6h01ct.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_lifecycle.md.Ccm5xw6-.js +14 -0
- package/docs/.vitepress/dist/assets/api_lifecycle.md.Ccm5xw6-.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_route.md.CAHf_KNp.js +10 -0
- package/docs/.vitepress/dist/assets/api_route.md.CAHf_KNp.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_vite-plugin.md.DNn9VhL5.js +13 -0
- package/docs/.vitepress/dist/assets/api_vite-plugin.md.DNn9VhL5.lean.js +1 -0
- package/docs/.vitepress/dist/assets/app.BG5s3B0P.js +1 -0
- package/docs/.vitepress/dist/assets/chunks/@localSearchIndexroot.DQmuWC2Z.js +1 -0
- package/docs/.vitepress/dist/assets/chunks/VPLocalSearchBox.BO-PSxt1.js +9 -0
- package/docs/.vitepress/dist/assets/chunks/framework.B7OFBR9X.js +19 -0
- package/docs/.vitepress/dist/assets/chunks/theme.DA-iSa9B.js +2 -0
- package/docs/.vitepress/dist/assets/examples_form.md.B3stGKbu.js +34 -0
- package/docs/.vitepress/dist/assets/examples_form.md.B3stGKbu.lean.js +1 -0
- package/docs/.vitepress/dist/assets/examples_index.md.BDEG_D4J.js +30 -0
- package/docs/.vitepress/dist/assets/examples_index.md.BDEG_D4J.lean.js +1 -0
- package/docs/.vitepress/dist/assets/examples_routing.md.bqZ9DjDK.js +338 -0
- package/docs/.vitepress/dist/assets/examples_routing.md.bqZ9DjDK.lean.js +1 -0
- package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DLXaUiop.js +13 -0
- package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DLXaUiop.lean.js +1 -0
- package/docs/.vitepress/dist/assets/examples_todo-app.md.D5RhZoo5.js +297 -0
- package/docs/.vitepress/dist/assets/examples_todo-app.md.D5RhZoo5.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CAjf03Lr.js +182 -0
- package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CAjf03Lr.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_components.md.BIFWF1Hc.js +174 -0
- package/docs/.vitepress/dist/assets/guide_components.md.BIFWF1Hc.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_contributing.md.BgbUN-Mr.js +1 -0
- package/docs/.vitepress/dist/assets/guide_contributing.md.BgbUN-Mr.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_directives.md.Bi3ynu1d.js +140 -0
- package/docs/.vitepress/dist/assets/guide_directives.md.Bi3ynu1d.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_getting-started.md.2Nr1lp2z.js +107 -0
- package/docs/.vitepress/dist/assets/guide_getting-started.md.2Nr1lp2z.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_index.md.GvZq_Yf2.js +2 -0
- package/docs/.vitepress/dist/assets/guide_index.md.GvZq_Yf2.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_lifecycle.md.B28j1OzS.js +304 -0
- package/docs/.vitepress/dist/assets/guide_lifecycle.md.B28j1OzS.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_quick-start.md.CNk3VGTF.js +33 -0
- package/docs/.vitepress/dist/assets/guide_quick-start.md.CNk3VGTF.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_reactivity.md.CVsaMaPv.js +135 -0
- package/docs/.vitepress/dist/assets/guide_reactivity.md.CVsaMaPv.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_routing.md.DSpDP25o.js +193 -0
- package/docs/.vitepress/dist/assets/guide_routing.md.DSpDP25o.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_sfc.md.CVUP66tS.js +187 -0
- package/docs/.vitepress/dist/assets/guide_sfc.md.CVUP66tS.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_templating.md.BgCGe4aa.js +119 -0
- package/docs/.vitepress/dist/assets/guide_templating.md.BgCGe4aa.lean.js +1 -0
- package/docs/.vitepress/dist/assets/index.md.xV1taCED.js +23 -0
- package/docs/.vitepress/dist/assets/index.md.xV1taCED.lean.js +1 -0
- package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/docs/.vitepress/dist/assets/style.eycE2Jhw.css +1 -0
- package/docs/.vitepress/dist/examples/form.html +58 -0
- package/docs/.vitepress/dist/examples/index.html +368 -0
- package/docs/.vitepress/dist/examples/routing.html +362 -0
- package/docs/.vitepress/dist/examples/sfc-showcase.html +37 -0
- package/docs/.vitepress/dist/examples/todo-app.html +321 -0
- package/docs/.vitepress/dist/guide/cdn-usage.html +206 -0
- package/docs/.vitepress/dist/guide/components.html +198 -0
- package/docs/.vitepress/dist/guide/contributing.html +25 -0
- package/docs/.vitepress/dist/guide/directives.html +164 -0
- package/docs/.vitepress/dist/guide/getting-started.html +131 -0
- package/docs/.vitepress/dist/guide/index.html +26 -0
- package/docs/.vitepress/dist/guide/lifecycle.html +328 -0
- package/docs/.vitepress/dist/guide/quick-start.html +57 -0
- package/docs/.vitepress/dist/guide/reactivity.html +159 -0
- package/docs/.vitepress/dist/guide/routing.html +217 -0
- package/docs/.vitepress/dist/guide/sfc.html +211 -0
- package/docs/.vitepress/dist/guide/templating.html +143 -0
- package/docs/.vitepress/dist/hashmap.json +1 -0
- package/docs/.vitepress/dist/index.html +47 -0
- package/docs/.vitepress/dist/logo.svg +38 -0
- package/docs/.vitepress/dist/vp-icons.css +1 -0
- package/docs/api/define.md +31 -0
- package/docs/api/directives.md +42 -0
- package/docs/api/globals.md +29 -0
- package/docs/api/index.md +29 -0
- package/docs/api/lifecycle.md +40 -0
- package/docs/api/route.md +37 -0
- package/docs/api/vite-plugin.md +58 -0
- package/docs/examples/form.md +42 -0
- package/docs/examples/index.md +104 -0
- package/docs/examples/routing.md +409 -0
- package/docs/examples/sfc-showcase.md +34 -0
- package/docs/examples/todo-app.md +383 -0
- package/docs/guide/cdn-usage.md +320 -0
- package/docs/guide/components.md +394 -0
- package/docs/guide/contributing.md +32 -0
- package/docs/guide/directives.md +430 -0
- package/docs/guide/getting-started.md +233 -0
- package/docs/guide/index.md +88 -0
- package/docs/guide/lifecycle.md +493 -0
- package/docs/guide/quick-start.md +46 -0
- package/docs/guide/reactivity.md +394 -0
- package/docs/guide/routing.md +373 -0
- package/docs/guide/sfc.md +381 -0
- package/docs/guide/templating.md +383 -0
- package/docs/index.md +126 -0
- package/docs/public/logo.svg +38 -0
- package/examples/vite-app/README.md +71 -0
- package/examples/vite-app/index.html +45 -0
- package/examples/vite-app/package.json +16 -0
- package/examples/vite-app/src/components/greeting-card.lego +41 -0
- package/examples/vite-app/src/components/sample-component.lego +75 -0
- package/examples/vite-app/src/main.js +11 -0
- package/examples/vite-app/vite.config.js +16 -0
- package/examples.js +99 -0
- package/package.json +34 -7
- package/parse-lego.js +119 -0
- package/parse-lego.test.js +107 -0
- package/vite-plugin.js +133 -0
- package/.ignore/auto.html +0 -135
- package/.ignore/test.html +0 -73
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
# Reactivity
|
|
2
|
+
|
|
3
|
+
Understand how LegoJS makes your UI automatically update when data changes.
|
|
4
|
+
|
|
5
|
+
## The Core Concept
|
|
6
|
+
|
|
7
|
+
When you change an object, the DOM updates automatically:
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
component._studs.count = 5; // DOM updates!
|
|
11
|
+
component._studs.items.push('new item'); // DOM updates!
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
No `setState()`, no `dispatch()`, no special syntax. Just mutate the data.
|
|
15
|
+
|
|
16
|
+
## How It Works
|
|
17
|
+
|
|
18
|
+
LegoJS uses **ES6 Proxies** to track changes:
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
const reactive = (obj, el) => {
|
|
22
|
+
return new Proxy(obj, {
|
|
23
|
+
set(target, key, value) {
|
|
24
|
+
const oldValue = target[key];
|
|
25
|
+
target[key] = value;
|
|
26
|
+
|
|
27
|
+
if (oldValue !== value) {
|
|
28
|
+
// Schedule re-render
|
|
29
|
+
render(el);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
When you set a property, the proxy intercepts it and schedules a re-render.
|
|
39
|
+
|
|
40
|
+
## What's Reactive
|
|
41
|
+
|
|
42
|
+
### ✅ Direct Property Assignment
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
this.count = 10; // ✅ Reactive
|
|
46
|
+
this.user.name = 'Alice'; // ✅ Reactive
|
|
47
|
+
this.items[0] = 'updated'; // ✅ Reactive
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### ✅ Array Methods
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
this.items.push('new'); // ✅ Reactive
|
|
54
|
+
this.items.pop(); // ✅ Reactive
|
|
55
|
+
this.items.splice(0, 1); // ✅ Reactive
|
|
56
|
+
this.items.sort(); // ✅ Reactive
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### ✅ Nested Objects
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
this.user.profile.age = 30; // ✅ Reactive
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
LegoJS recursively wraps nested objects in proxies.
|
|
66
|
+
|
|
67
|
+
### ✅ Object Deletion
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
delete this.user.email; // ✅ Reactive
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### ⚠️ Limitations
|
|
74
|
+
|
|
75
|
+
#### Replacing Arrays
|
|
76
|
+
|
|
77
|
+
Don't replace the entire array reference:
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
this.items = newItems; // ⚠️ Might not be reactive
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Instead, mutate in place:
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
this.items.length = 0;
|
|
87
|
+
this.items.push(...newItems); // ✅ Better
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### Adding New Root Properties
|
|
91
|
+
|
|
92
|
+
Adding properties after initialization won't be reactive:
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
// Initial state
|
|
96
|
+
{
|
|
97
|
+
count: 0
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Later...
|
|
101
|
+
this.newProp = 'value'; // ⚠️ Not reactive
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Initialize all properties upfront:
|
|
105
|
+
|
|
106
|
+
```js
|
|
107
|
+
{
|
|
108
|
+
count: 0,
|
|
109
|
+
newProp: null // ✅ Initialize with default
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Batching Updates
|
|
114
|
+
|
|
115
|
+
LegoJS batches updates using `requestAnimationFrame`:
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
this.count = 1;
|
|
119
|
+
this.count = 2;
|
|
120
|
+
this.count = 3;
|
|
121
|
+
// Only one re-render happens!
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
This prevents unnecessary DOM updates and improves performance.
|
|
125
|
+
|
|
126
|
+
## Update Lifecycle
|
|
127
|
+
|
|
128
|
+
1. **State Change** - You mutate data
|
|
129
|
+
2. **Proxy Intercepts** - Change is detected
|
|
130
|
+
3. **Batch Queue** - Component added to update queue
|
|
131
|
+
4. **requestAnimationFrame** - Browser schedules render
|
|
132
|
+
5. **Re-render** - DOM is updated
|
|
133
|
+
6. **updated() Hook** - Called after render
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
{
|
|
137
|
+
count: 0,
|
|
138
|
+
|
|
139
|
+
increment() {
|
|
140
|
+
console.log('Before:', this.count);
|
|
141
|
+
this.count++;
|
|
142
|
+
console.log('After:', this.count);
|
|
143
|
+
// DOM not updated yet!
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
updated() {
|
|
147
|
+
console.log('DOM updated with:', this.count);
|
|
148
|
+
// DOM is updated now!
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Deep Reactivity
|
|
154
|
+
|
|
155
|
+
Nested objects are automatically reactive:
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
{
|
|
159
|
+
user: {
|
|
160
|
+
profile: {
|
|
161
|
+
settings: {
|
|
162
|
+
theme: 'dark'
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```html
|
|
170
|
+
<!-- All reactive -->
|
|
171
|
+
<p>{{ user.profile.settings.theme }}</p>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
this.user.profile.settings.theme = 'light'; // ✅ Updates DOM
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Arrays and Objects
|
|
179
|
+
|
|
180
|
+
### Array Mutations
|
|
181
|
+
|
|
182
|
+
All mutating methods trigger updates:
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
this.items.push(newItem);
|
|
186
|
+
this.items.pop();
|
|
187
|
+
this.items.shift();
|
|
188
|
+
this.items.unshift(item);
|
|
189
|
+
this.items.splice(index, 1);
|
|
190
|
+
this.items.sort();
|
|
191
|
+
this.items.reverse();
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Non-Mutating Methods
|
|
195
|
+
|
|
196
|
+
These don't trigger updates (they return new arrays):
|
|
197
|
+
|
|
198
|
+
```js
|
|
199
|
+
const filtered = this.items.filter(x => x.active); // No update
|
|
200
|
+
const mapped = this.items.map(x => x.name); // No update
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
To make them reactive, assign back:
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
this.items = this.items.filter(x => x.active); // ✅ Triggers update
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Or use mutating equivalents:
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
// Instead of filter
|
|
213
|
+
for (let i = this.items.length - 1; i >= 0; i--) {
|
|
214
|
+
if (!this.items[i].active) {
|
|
215
|
+
this.items.splice(i, 1); // ✅ Reactive
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Object Changes
|
|
221
|
+
|
|
222
|
+
### Adding Properties to Nested Objects
|
|
223
|
+
|
|
224
|
+
```js
|
|
225
|
+
this.user.newProp = 'value'; // ✅ Reactive (nested object)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Object.assign()
|
|
229
|
+
|
|
230
|
+
```js
|
|
231
|
+
Object.assign(this.user, { name: 'Alice', age: 30 }); // ✅ Reactive
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Performance Considerations
|
|
235
|
+
|
|
236
|
+
### Minimize Unnecessary Updates
|
|
237
|
+
|
|
238
|
+
Group related changes:
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
// ❌ Bad - 3 separate updates
|
|
242
|
+
this.user.name = 'Alice';
|
|
243
|
+
this.user.age = 30;
|
|
244
|
+
this.user.email = 'alice@example.com';
|
|
245
|
+
|
|
246
|
+
// ✅ Better - 1 update
|
|
247
|
+
Object.assign(this.user, {
|
|
248
|
+
name: 'Alice',
|
|
249
|
+
age: 30,
|
|
250
|
+
email: 'alice@example.com'
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Avoid Reactive Overhead for Static Data
|
|
255
|
+
|
|
256
|
+
Don't make everything reactive:
|
|
257
|
+
|
|
258
|
+
```js
|
|
259
|
+
{
|
|
260
|
+
// Reactive data
|
|
261
|
+
count: 0,
|
|
262
|
+
|
|
263
|
+
// Constants (not reactive, but that's fine)
|
|
264
|
+
MAX_COUNT: 100,
|
|
265
|
+
API_URL: 'https://api.example.com'
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Debugging Reactivity
|
|
270
|
+
|
|
271
|
+
### Check if Value Changed
|
|
272
|
+
|
|
273
|
+
```js
|
|
274
|
+
{
|
|
275
|
+
count: 0,
|
|
276
|
+
|
|
277
|
+
updated() {
|
|
278
|
+
console.log('Count changed to:', this.count);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Inspect Proxy
|
|
284
|
+
|
|
285
|
+
```js
|
|
286
|
+
console.log(component._studs); // Proxy object
|
|
287
|
+
console.log(component._studs.count); // Actual value
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Comparing with Other Frameworks
|
|
291
|
+
|
|
292
|
+
### Vue 3
|
|
293
|
+
|
|
294
|
+
```js
|
|
295
|
+
// Vue 3
|
|
296
|
+
const count = ref(0);
|
|
297
|
+
count.value++;
|
|
298
|
+
|
|
299
|
+
// LegoJS
|
|
300
|
+
this.count++;
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### React
|
|
304
|
+
|
|
305
|
+
```js
|
|
306
|
+
// React
|
|
307
|
+
const [count, setCount] = useState(0);
|
|
308
|
+
setCount(count + 1);
|
|
309
|
+
|
|
310
|
+
// LegoJS
|
|
311
|
+
this.count++;
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Svelte
|
|
315
|
+
|
|
316
|
+
```js
|
|
317
|
+
// Svelte
|
|
318
|
+
let count = 0;
|
|
319
|
+
count++;
|
|
320
|
+
|
|
321
|
+
// LegoJS
|
|
322
|
+
this.count++;
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
LegoJS is closest to Svelte's model but uses Proxies instead of compilation.
|
|
326
|
+
|
|
327
|
+
## Advanced Patterns
|
|
328
|
+
|
|
329
|
+
### Watching for Changes
|
|
330
|
+
|
|
331
|
+
Use `updated()` hook:
|
|
332
|
+
|
|
333
|
+
```js
|
|
334
|
+
{
|
|
335
|
+
count: 0,
|
|
336
|
+
previousCount: 0,
|
|
337
|
+
|
|
338
|
+
updated() {
|
|
339
|
+
if (this.count !== this.previousCount) {
|
|
340
|
+
console.log('Count changed from', this.previousCount, 'to', this.count);
|
|
341
|
+
this.previousCount = this.count;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Computed Properties
|
|
348
|
+
|
|
349
|
+
Use methods:
|
|
350
|
+
|
|
351
|
+
```js
|
|
352
|
+
{
|
|
353
|
+
firstName: 'John',
|
|
354
|
+
lastName: 'Doe',
|
|
355
|
+
|
|
356
|
+
fullName() {
|
|
357
|
+
return `${this.firstName} ${this.lastName}`;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
```html
|
|
363
|
+
<p>{{ fullName() }}</p>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Debouncing Updates
|
|
367
|
+
|
|
368
|
+
```js
|
|
369
|
+
{
|
|
370
|
+
searchQuery: '',
|
|
371
|
+
timer: null,
|
|
372
|
+
|
|
373
|
+
onInput() {
|
|
374
|
+
clearTimeout(this.timer);
|
|
375
|
+
this.timer = setTimeout(() => {
|
|
376
|
+
this.performSearch();
|
|
377
|
+
}, 300);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## Best Practices
|
|
383
|
+
|
|
384
|
+
1. **Initialize all properties** - Define them upfront
|
|
385
|
+
2. **Use array methods** - push(), splice(), etc.
|
|
386
|
+
3. **Batch related changes** - Use Object.assign()
|
|
387
|
+
4. **Keep state flat when possible** - Shallow is faster
|
|
388
|
+
5. **Use methods for computed values** - They're called on every render
|
|
389
|
+
|
|
390
|
+
## Next Steps
|
|
391
|
+
|
|
392
|
+
- Learn about [Templating](/guide/templating)
|
|
393
|
+
- Explore [Directives](/guide/directives)
|
|
394
|
+
- See [reactivity examples](/examples/)
|