jac-client 0.1.0__py3-none-any.whl
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.
- jac_client/docs/README.md +629 -0
- jac_client/docs/advanced-state.md +706 -0
- jac_client/docs/imports.md +650 -0
- jac_client/docs/lifecycle-hooks.md +554 -0
- jac_client/docs/routing.md +530 -0
- jac_client/examples/little-x/app.jac +615 -0
- jac_client/examples/little-x/package-lock.json +2840 -0
- jac_client/examples/little-x/package.json +23 -0
- jac_client/examples/little-x/submit-button.jac +8 -0
- jac_client/examples/todo-app/README.md +82 -0
- jac_client/examples/todo-app/app.jac +683 -0
- jac_client/examples/todo-app/package-lock.json +999 -0
- jac_client/examples/todo-app/package.json +22 -0
- jac_client/plugin/cli.py +328 -0
- jac_client/plugin/client.py +41 -0
- jac_client/plugin/client_runtime.jac +941 -0
- jac_client/plugin/vite_client_bundle.py +470 -0
- jac_client/tests/__init__.py +2 -0
- jac_client/tests/fixtures/button.jac +6 -0
- jac_client/tests/fixtures/client_app.jac +18 -0
- jac_client/tests/fixtures/client_app_with_antd.jac +21 -0
- jac_client/tests/fixtures/js_import.jac +30 -0
- jac_client/tests/fixtures/package-lock.json +329 -0
- jac_client/tests/fixtures/package.json +11 -0
- jac_client/tests/fixtures/relative_import.jac +13 -0
- jac_client/tests/fixtures/test_fragments_spread.jac +44 -0
- jac_client/tests/fixtures/utils.js +22 -0
- jac_client/tests/test_cl.py +360 -0
- jac_client/tests/test_create_jac_app.py +139 -0
- jac_client-0.1.0.dist-info/METADATA +126 -0
- jac_client-0.1.0.dist-info/RECORD +33 -0
- jac_client-0.1.0.dist-info/WHEEL +4 -0
- jac_client-0.1.0.dist-info/entry_points.txt +4 -0
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
# Lifecycle Hooks in Jac: Component Lifecycle Management
|
|
2
|
+
|
|
3
|
+
Learn how to use `onMount()` and other lifecycle hooks to manage component initialization, side effects, and cleanup.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📚 Table of Contents
|
|
8
|
+
|
|
9
|
+
- [What are Lifecycle Hooks?](#what-are-lifecycle-hooks)
|
|
10
|
+
- [The `onMount()` Hook](#the-onmount-hook)
|
|
11
|
+
- [Common Use Cases](#common-use-cases)
|
|
12
|
+
- [Complete Examples](#complete-examples)
|
|
13
|
+
- [Best Practices](#best-practices)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## What are Lifecycle Hooks?
|
|
18
|
+
|
|
19
|
+
Lifecycle hooks are functions that let you run code at specific points in a component's lifecycle:
|
|
20
|
+
- **When component mounts**: Run initialization code once
|
|
21
|
+
- **When component updates**: React to state changes
|
|
22
|
+
- **When component unmounts**: Clean up resources
|
|
23
|
+
|
|
24
|
+
In Jac, the primary lifecycle hook is `onMount()`, which runs code once when a component first renders.
|
|
25
|
+
|
|
26
|
+
**Key Benefits:**
|
|
27
|
+
- **Initialization**: Load data when component appears
|
|
28
|
+
- **Side Effects**: Set up subscriptions, timers, or listeners
|
|
29
|
+
- **One-Time Setup**: Ensure code runs only once, not on every render
|
|
30
|
+
- **Component Scoping**: Automatically tracks which component called the hook
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## The `onMount()` Hook
|
|
35
|
+
|
|
36
|
+
### Basic Usage
|
|
37
|
+
|
|
38
|
+
```jac
|
|
39
|
+
cl {
|
|
40
|
+
def MyComponent() -> any {
|
|
41
|
+
onMount(lambda -> None {
|
|
42
|
+
console.log("Component mounted!");
|
|
43
|
+
# Load initial data
|
|
44
|
+
loadData();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return <div>My Component</div>;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**How it Works:**
|
|
53
|
+
1. Component renders
|
|
54
|
+
2. `onMount()` is called
|
|
55
|
+
3. The provided function runs **once** after the component is fully rendered
|
|
56
|
+
4. Function won't run again on re-renders
|
|
57
|
+
|
|
58
|
+
### Key Characteristics
|
|
59
|
+
|
|
60
|
+
- **Runs Once**: Executes only on the first render
|
|
61
|
+
- **After Render**: Runs after the component is mounted to the DOM
|
|
62
|
+
- **Component Scoped**: Automatically tracks which component called it
|
|
63
|
+
- **Async Support**: Can contain async operations
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Common Use Cases
|
|
68
|
+
|
|
69
|
+
### 1. Loading Initial Data
|
|
70
|
+
|
|
71
|
+
The most common use case is loading data when a component mounts:
|
|
72
|
+
|
|
73
|
+
```jac
|
|
74
|
+
cl {
|
|
75
|
+
let [todoState, setTodoState] = createState({
|
|
76
|
+
"items": [],
|
|
77
|
+
"loading": True
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
async def loadTodos() -> None {
|
|
81
|
+
setTodoState({"loading": True});
|
|
82
|
+
|
|
83
|
+
# Fetch todos from backend
|
|
84
|
+
todos = await __jacSpawn("read_todos");
|
|
85
|
+
|
|
86
|
+
items = [];
|
|
87
|
+
for todo in todos.reports {
|
|
88
|
+
items.push({
|
|
89
|
+
"id": todo._jac_id,
|
|
90
|
+
"text": todo.text,
|
|
91
|
+
"done": todo.done
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
setTodoState({"items": items, "loading": False});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
def TodoApp() -> any {
|
|
99
|
+
# Load todos when component mounts
|
|
100
|
+
onMount(lambda -> None {
|
|
101
|
+
loadTodos();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
s = todoState();
|
|
105
|
+
|
|
106
|
+
if s.loading {
|
|
107
|
+
return <div>Loading...</div>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return <div>
|
|
111
|
+
{[TodoItem(item) for item in s.items]}
|
|
112
|
+
</div>;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 2. Setting Up Event Listeners
|
|
118
|
+
|
|
119
|
+
Set up event listeners that need to persist across re-renders:
|
|
120
|
+
|
|
121
|
+
```jac
|
|
122
|
+
cl {
|
|
123
|
+
def WindowResizeHandler() -> any {
|
|
124
|
+
let [windowSize, setWindowSize] = createState({
|
|
125
|
+
"width": 0,
|
|
126
|
+
"height": 0
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
def handleResize() -> None {
|
|
130
|
+
setWindowSize({
|
|
131
|
+
"width": window.innerWidth,
|
|
132
|
+
"height": window.innerHeight
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
def ResizeDisplay() -> any {
|
|
137
|
+
onMount(lambda -> None {
|
|
138
|
+
# Set initial size
|
|
139
|
+
handleResize();
|
|
140
|
+
|
|
141
|
+
# Add listener
|
|
142
|
+
window.addEventListener("resize", handleResize);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
s = windowSize();
|
|
146
|
+
return <div>
|
|
147
|
+
Window size: {s.width} x {s.height}
|
|
148
|
+
</div>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return ResizeDisplay();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 3. Fetching User Data
|
|
157
|
+
|
|
158
|
+
Load user-specific data when a component mounts:
|
|
159
|
+
|
|
160
|
+
```jac
|
|
161
|
+
cl {
|
|
162
|
+
let [userState, setUserState] = createState({
|
|
163
|
+
"profile": None,
|
|
164
|
+
"loading": True
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
async def loadUserProfile() -> None {
|
|
168
|
+
if not jacIsLoggedIn() {
|
|
169
|
+
navigate("/login");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# Fetch user profile
|
|
174
|
+
profile = await __jacSpawn("get_user_profile");
|
|
175
|
+
|
|
176
|
+
setUserState({
|
|
177
|
+
"profile": profile,
|
|
178
|
+
"loading": False
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
def ProfileView() -> any {
|
|
183
|
+
onMount(lambda -> None {
|
|
184
|
+
loadUserProfile();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
s = userState();
|
|
188
|
+
|
|
189
|
+
if s.loading {
|
|
190
|
+
return <div>Loading profile...</div>;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if not s.profile {
|
|
194
|
+
return <div>No profile found</div>;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return <div>
|
|
198
|
+
<h1>{s.profile.username}</h1>
|
|
199
|
+
<p>{s.profile.email}</p>
|
|
200
|
+
</div>;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 4. Initializing Third-Party Libraries
|
|
206
|
+
|
|
207
|
+
Initialize external libraries or APIs:
|
|
208
|
+
|
|
209
|
+
```jac
|
|
210
|
+
cl {
|
|
211
|
+
def ChartComponent() -> any {
|
|
212
|
+
onMount(lambda -> None {
|
|
213
|
+
# Initialize chart library
|
|
214
|
+
chart = new Chart("myChart", {
|
|
215
|
+
"type": "line",
|
|
216
|
+
"data": chartData,
|
|
217
|
+
"options": chartOptions
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
return <canvas id="myChart"></canvas>;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 5. Focusing Input Fields
|
|
227
|
+
|
|
228
|
+
Focus an input field when a component mounts:
|
|
229
|
+
|
|
230
|
+
```jac
|
|
231
|
+
cl {
|
|
232
|
+
def SearchBar() -> any {
|
|
233
|
+
onMount(lambda -> None {
|
|
234
|
+
# Focus search input on mount
|
|
235
|
+
inputEl = document.getElementById("search-input");
|
|
236
|
+
if inputEl {
|
|
237
|
+
inputEl.focus();
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
return <input
|
|
242
|
+
id="search-input"
|
|
243
|
+
type="text"
|
|
244
|
+
placeholder="Search..."
|
|
245
|
+
/>;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Complete Examples
|
|
253
|
+
|
|
254
|
+
### Example 1: Todo App with Data Loading
|
|
255
|
+
|
|
256
|
+
```jac
|
|
257
|
+
cl {
|
|
258
|
+
let [todoState, setTodoState] = createState({
|
|
259
|
+
"items": [],
|
|
260
|
+
"filter": "all",
|
|
261
|
+
"loading": False
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
async def read_todos_action() -> None {
|
|
265
|
+
setTodoState({"loading": True});
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
todos = await __jacSpawn("read_todos");
|
|
269
|
+
|
|
270
|
+
items = [];
|
|
271
|
+
for todo in todos.reports {
|
|
272
|
+
items.push({
|
|
273
|
+
"id": todo._jac_id,
|
|
274
|
+
"text": todo.text,
|
|
275
|
+
"done": todo.done
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
setTodoState({"items": items, "loading": False});
|
|
280
|
+
} except Exception as err {
|
|
281
|
+
console.error("Failed to load todos:", err);
|
|
282
|
+
setTodoState({"loading": False});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
def TodoApp() -> any {
|
|
287
|
+
# Load todos when component mounts
|
|
288
|
+
onMount(lambda -> None {
|
|
289
|
+
read_todos_action();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
s = todoState();
|
|
293
|
+
|
|
294
|
+
if s.loading {
|
|
295
|
+
return <div style={{
|
|
296
|
+
"textAlign": "center",
|
|
297
|
+
"padding": "40px"
|
|
298
|
+
}}>
|
|
299
|
+
Loading todos...
|
|
300
|
+
</div>;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
itemsArr = filteredItems();
|
|
304
|
+
children = [];
|
|
305
|
+
for it in itemsArr {
|
|
306
|
+
children.push(TodoItem(it));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return <div>
|
|
310
|
+
<h2>My Todos</h2>
|
|
311
|
+
<form onSubmit={onAddTodo}>
|
|
312
|
+
<input id="todo-input" type="text" />
|
|
313
|
+
<button type="submit">Add Todo</button>
|
|
314
|
+
</form>
|
|
315
|
+
<ul>{children}</ul>
|
|
316
|
+
</div>;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Example 2: Dashboard with Multiple Data Sources
|
|
322
|
+
|
|
323
|
+
```jac
|
|
324
|
+
cl {
|
|
325
|
+
let [dashboardState, setDashboardState] = createState({
|
|
326
|
+
"stats": None,
|
|
327
|
+
"recentActivity": [],
|
|
328
|
+
"loading": True
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
async def loadDashboardData() -> None {
|
|
332
|
+
setDashboardState({"loading": True});
|
|
333
|
+
|
|
334
|
+
# Load multiple data sources in parallel
|
|
335
|
+
[stats, activity] = await Promise.all([
|
|
336
|
+
__jacSpawn("get_stats"),
|
|
337
|
+
__jacSpawn("get_recent_activity")
|
|
338
|
+
]);
|
|
339
|
+
|
|
340
|
+
setDashboardState({
|
|
341
|
+
"stats": stats,
|
|
342
|
+
"recentActivity": activity.reports,
|
|
343
|
+
"loading": False
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
def Dashboard() -> any {
|
|
348
|
+
# Load all dashboard data on mount
|
|
349
|
+
onMount(lambda -> None {
|
|
350
|
+
loadDashboardData();
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
s = dashboardState();
|
|
354
|
+
|
|
355
|
+
if s.loading {
|
|
356
|
+
return <div>Loading dashboard...</div>;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return <div>
|
|
360
|
+
<StatsView stats={s.stats} />
|
|
361
|
+
<ActivityList activities={s.recentActivity} />
|
|
362
|
+
</div>;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Example 3: Component with Cleanup (Future)
|
|
368
|
+
|
|
369
|
+
While `onMount()` doesn't currently support cleanup directly, you can store cleanup functions:
|
|
370
|
+
|
|
371
|
+
```jac
|
|
372
|
+
cl {
|
|
373
|
+
let cleanupFunctions = [];
|
|
374
|
+
|
|
375
|
+
def TimerComponent() -> any {
|
|
376
|
+
onMount(lambda -> None {
|
|
377
|
+
# Set up timer
|
|
378
|
+
intervalId = setInterval(lambda -> None {
|
|
379
|
+
console.log("Timer tick");
|
|
380
|
+
}, 1000);
|
|
381
|
+
|
|
382
|
+
# Store cleanup function
|
|
383
|
+
cleanupFunctions.push(lambda -> None {
|
|
384
|
+
clearInterval(intervalId);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
return <div>Timer Component</div>;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Best Practices
|
|
396
|
+
|
|
397
|
+
### 1. Use `onMount()` for Initialization Only
|
|
398
|
+
|
|
399
|
+
```jac
|
|
400
|
+
# ✅ Good: One-time initialization
|
|
401
|
+
def Component() -> any {
|
|
402
|
+
onMount(lambda -> None {
|
|
403
|
+
loadInitialData();
|
|
404
|
+
});
|
|
405
|
+
return <div>Component</div>;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
# ❌ Avoid: Side effects that should run on every state change
|
|
409
|
+
def Component() -> any {
|
|
410
|
+
s = state();
|
|
411
|
+
onMount(lambda -> None {
|
|
412
|
+
# This won't run when state changes!
|
|
413
|
+
processState(s);
|
|
414
|
+
});
|
|
415
|
+
return <div>{s.value}</div>;
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### 2. Handle Async Operations
|
|
420
|
+
|
|
421
|
+
Always handle async operations properly:
|
|
422
|
+
|
|
423
|
+
```jac
|
|
424
|
+
# ✅ Good: Handle async properly
|
|
425
|
+
async def loadData() -> None {
|
|
426
|
+
try {
|
|
427
|
+
data = await __jacSpawn("get_data");
|
|
428
|
+
setState({"data": data});
|
|
429
|
+
} except Exception as err {
|
|
430
|
+
console.error("Error loading data:", err);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
def Component() -> any {
|
|
435
|
+
onMount(lambda -> None {
|
|
436
|
+
loadData();
|
|
437
|
+
});
|
|
438
|
+
return <div>Component</div>;
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### 3. Check Conditions Before Operations
|
|
443
|
+
|
|
444
|
+
Verify prerequisites before executing operations:
|
|
445
|
+
|
|
446
|
+
```jac
|
|
447
|
+
# ✅ Good: Check authentication first
|
|
448
|
+
def ProtectedComponent() -> any {
|
|
449
|
+
onMount(lambda -> None {
|
|
450
|
+
if not jacIsLoggedIn() {
|
|
451
|
+
navigate("/login");
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
loadUserData();
|
|
455
|
+
});
|
|
456
|
+
return <div>Protected Content</div>;
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### 4. Use Loading States
|
|
461
|
+
|
|
462
|
+
Show loading indicators while data is being fetched:
|
|
463
|
+
|
|
464
|
+
```jac
|
|
465
|
+
def Component() -> any {
|
|
466
|
+
let [dataState, setDataState] = createState({
|
|
467
|
+
"data": None,
|
|
468
|
+
"loading": True
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
onMount(lambda -> None {
|
|
472
|
+
loadData();
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
s = dataState();
|
|
476
|
+
if s.loading {
|
|
477
|
+
return <div>Loading...</div>;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return <div>{s.data}</div>;
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### 5. Avoid Multiple `onMount()` Calls
|
|
485
|
+
|
|
486
|
+
Group initialization logic in a single `onMount()` call:
|
|
487
|
+
|
|
488
|
+
```jac
|
|
489
|
+
# ✅ Good: Single onMount with multiple operations
|
|
490
|
+
def Component() -> any {
|
|
491
|
+
onMount(lambda -> None {
|
|
492
|
+
loadData();
|
|
493
|
+
setupEventListeners();
|
|
494
|
+
initializeThirdParty();
|
|
495
|
+
});
|
|
496
|
+
return <div>Component</div>;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
# ❌ Avoid: Multiple onMount calls
|
|
500
|
+
def Component() -> any {
|
|
501
|
+
onMount(lambda -> None { loadData(); });
|
|
502
|
+
onMount(lambda -> None { setupEventListeners(); });
|
|
503
|
+
onMount(lambda -> None { initializeThirdParty(); });
|
|
504
|
+
return <div>Component</div>;
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## When NOT to Use `onMount()`
|
|
511
|
+
|
|
512
|
+
### Use `createEffect()` for Reactive Side Effects
|
|
513
|
+
|
|
514
|
+
If you need code to run when state changes, use `createEffect()` instead:
|
|
515
|
+
|
|
516
|
+
```jac
|
|
517
|
+
# ✅ Use createEffect() for state-dependent side effects
|
|
518
|
+
def Component() -> any {
|
|
519
|
+
let [count, setCount] = createSignal(0);
|
|
520
|
+
|
|
521
|
+
createEffect(lambda -> None {
|
|
522
|
+
console.log("Count changed:", count());
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
return <div>
|
|
526
|
+
<button onClick={lambda -> None { setCount(count() + 1); }}>
|
|
527
|
+
Count: {count()}
|
|
528
|
+
</button>
|
|
529
|
+
</div>;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
# ❌ onMount() won't run when state changes
|
|
533
|
+
def Component() -> any {
|
|
534
|
+
let [count, setCount] = createSignal(0);
|
|
535
|
+
|
|
536
|
+
onMount(lambda -> None {
|
|
537
|
+
console.log("Count:", count()); # Only logs initial value
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
return <div>Component</div>;
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
## Summary
|
|
547
|
+
|
|
548
|
+
- **`onMount()`**: Runs code once when a component first mounts
|
|
549
|
+
- **Use Cases**: Loading data, setting up listeners, initializing libraries
|
|
550
|
+
- **Best Practices**: Handle async properly, check conditions, show loading states
|
|
551
|
+
- **Avoid**: Using `onMount()` for reactive side effects (use `createEffect()` instead)
|
|
552
|
+
|
|
553
|
+
Lifecycle hooks help you manage component initialization and side effects effectively! 🎯
|
|
554
|
+
|