jac-client 0.2.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.
Files changed (72) hide show
  1. jac_client/docs/README.md +659 -0
  2. jac_client/docs/advanced-state.md +1266 -0
  3. jac_client/docs/assets/pipe_line.png +0 -0
  4. jac_client/docs/guide-example/intro.md +117 -0
  5. jac_client/docs/guide-example/step-01-setup.md +260 -0
  6. jac_client/docs/guide-example/step-02-components.md +416 -0
  7. jac_client/docs/guide-example/step-03-styling.md +478 -0
  8. jac_client/docs/guide-example/step-04-todo-ui.md +477 -0
  9. jac_client/docs/guide-example/step-05-local-state.md +530 -0
  10. jac_client/docs/guide-example/step-06-events.md +750 -0
  11. jac_client/docs/guide-example/step-07-effects.md +469 -0
  12. jac_client/docs/guide-example/step-08-walkers.md +534 -0
  13. jac_client/docs/guide-example/step-09-authentication.md +586 -0
  14. jac_client/docs/guide-example/step-10-routing.md +540 -0
  15. jac_client/docs/guide-example/step-11-final.md +964 -0
  16. jac_client/docs/imports.md +1142 -0
  17. jac_client/docs/lifecycle-hooks.md +774 -0
  18. jac_client/docs/routing.md +660 -0
  19. jac_client/examples/basic/.babelrc +9 -0
  20. jac_client/examples/basic/README.md +16 -0
  21. jac_client/examples/basic/app.jac +16 -0
  22. jac_client/examples/basic/package.json +27 -0
  23. jac_client/examples/basic/vite.config.js +28 -0
  24. jac_client/examples/basic-auth/.babelrc +9 -0
  25. jac_client/examples/basic-auth/README.md +16 -0
  26. jac_client/examples/basic-auth/app.jac +308 -0
  27. jac_client/examples/basic-auth/package.json +27 -0
  28. jac_client/examples/basic-auth/vite.config.js +28 -0
  29. jac_client/examples/basic-auth-with-router/.babelrc +9 -0
  30. jac_client/examples/basic-auth-with-router/README.md +60 -0
  31. jac_client/examples/basic-auth-with-router/app.jac +464 -0
  32. jac_client/examples/basic-auth-with-router/package.json +28 -0
  33. jac_client/examples/basic-auth-with-router/vite.config.js +28 -0
  34. jac_client/examples/basic-full-stack/.babelrc +9 -0
  35. jac_client/examples/basic-full-stack/README.md +18 -0
  36. jac_client/examples/basic-full-stack/app.jac +320 -0
  37. jac_client/examples/basic-full-stack/package.json +28 -0
  38. jac_client/examples/basic-full-stack/vite.config.js +28 -0
  39. jac_client/examples/full-stack-with-auth/.babelrc +9 -0
  40. jac_client/examples/full-stack-with-auth/README.md +16 -0
  41. jac_client/examples/full-stack-with-auth/app.jac +735 -0
  42. jac_client/examples/full-stack-with-auth/package.json +28 -0
  43. jac_client/examples/full-stack-with-auth/vite.config.js +30 -0
  44. jac_client/examples/little-x/app.jac +615 -0
  45. jac_client/examples/little-x/package.json +23 -0
  46. jac_client/examples/little-x/submit-button.jac +8 -0
  47. jac_client/examples/with-router/.babelrc +9 -0
  48. jac_client/examples/with-router/README.md +17 -0
  49. jac_client/examples/with-router/app.jac +323 -0
  50. jac_client/examples/with-router/package.json +28 -0
  51. jac_client/examples/with-router/vite.config.js +28 -0
  52. jac_client/plugin/cli.py +239 -0
  53. jac_client/plugin/client.py +89 -0
  54. jac_client/plugin/client_runtime.jac +234 -0
  55. jac_client/plugin/vite_client_bundle.py +355 -0
  56. jac_client/tests/__init__.py +2 -0
  57. jac_client/tests/fixtures/basic-app/app.jac +18 -0
  58. jac_client/tests/fixtures/client_app_with_antd/app.jac +28 -0
  59. jac_client/tests/fixtures/js_import/app.jac +30 -0
  60. jac_client/tests/fixtures/js_import/utils.js +22 -0
  61. jac_client/tests/fixtures/package-lock.json +329 -0
  62. jac_client/tests/fixtures/package.json +11 -0
  63. jac_client/tests/fixtures/relative_import/app.jac +13 -0
  64. jac_client/tests/fixtures/relative_import/button.jac +6 -0
  65. jac_client/tests/fixtures/spawn_test/app.jac +133 -0
  66. jac_client/tests/fixtures/test_fragments_spread/app.jac +53 -0
  67. jac_client/tests/test_cl.py +476 -0
  68. jac_client/tests/test_create_jac_app.py +139 -0
  69. jac_client-0.2.0.dist-info/METADATA +182 -0
  70. jac_client-0.2.0.dist-info/RECORD +72 -0
  71. jac_client-0.2.0.dist-info/WHEEL +4 -0
  72. jac_client-0.2.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,659 @@
1
+ # Todo App - Beginner's Guide to Building with Jac
2
+
3
+ Welcome to the Todo App example! This guide will walk you through building a full-stack web application with Jac, from setup to deployment. Jac simplifies web development by eliminating the need for separate frontend and backend technologies, HTTP clients, and complex build configurations.
4
+
5
+ ---
6
+
7
+ ## 📦 1. Creating the Application
8
+
9
+ ### Installation
10
+
11
+ First, install the Jac client package:
12
+
13
+ ```bash
14
+ pip install jac-client
15
+ ```
16
+
17
+ ### Create a New Jac App
18
+
19
+ Use the `jac create_jac_app` command to scaffold a new application: (* we can name our app however we want, here we are using `todo-app)
20
+
21
+ ```bash
22
+ jac create_jac_app todo-app
23
+ ```
24
+
25
+ This command will:
26
+ - Create a new directory with your project name
27
+ - Set up the basic project structure
28
+ - Initialize npm and install Vite (for development server)
29
+ - Create a starter `app.jac` file with a sample component
30
+
31
+ **What gets created:**
32
+ ```
33
+ my-app/
34
+ ├── app.jac # Your main application file
35
+ ├── package.json # Node.js dependencies
36
+ └── node_modules/ # Dependencies (after npm install)
37
+ ```
38
+
39
+ ### Running Your App
40
+
41
+ Navigate to your project directory and start the development server:
42
+
43
+ ```bash
44
+ cd todo-app
45
+ jac serve app.jac
46
+ ```
47
+
48
+ This starts both:
49
+ - **Backend server**: Handles your Jac graph operations and walkers
50
+ - **Frontend development server**: Serves your React components
51
+
52
+ You can access your app at `http://localhost:8000`
53
+
54
+ ---
55
+
56
+ ## 🚪 2. Entry Point of the App
57
+
58
+ Every Jac client application needs an entry point function. This is where your app starts rendering.
59
+
60
+ ### The `app()` Function
61
+
62
+ Inside your `cl` block, define a function called `app()`:
63
+
64
+ ```jac
65
+ cl import from react {useState}
66
+
67
+ cl {
68
+ def app() -> any {
69
+ let [count, setCount] = useState(0);
70
+ return <div>
71
+ <h1>Hello, World!</h1>
72
+ <p>Count: {count}</p>
73
+ <button onClick={lambda e: any -> None { setCount(count + 1); }}>
74
+ Increment
75
+ </button>
76
+ </div>;
77
+ }
78
+ }
79
+ ```
80
+
81
+ **Key Points:**
82
+ - `app()` is the **required entry point** that Jac looks for
83
+ - It must be defined inside a `cl { }` block (client-side code)
84
+ - The `cl` (client) block indicates this code runs in the browser
85
+ - This function gets called automatically when the page loads
86
+ - You can define other components and helper functions in the same `cl` block
87
+
88
+ **Example with Multiple Components:**
89
+ ```jac
90
+ cl import from react {useState, useEffect}
91
+
92
+ cl {
93
+ def TodoList(todos: list) -> any {
94
+ return <ul>
95
+ {todos.map(lambda todo: any -> any {
96
+ return <li key={todo._jac_id}>{todo.text}</li>;
97
+ })}
98
+ </ul>;
99
+ }
100
+
101
+ def app() -> any {
102
+ let [todos, setTodos] = useState([]);
103
+
104
+ useEffect(lambda -> None {
105
+ async def loadTodos() -> None {
106
+ result = root spawn read_todos();
107
+ setTodos(result.reports if result.reports else []);
108
+ }
109
+ loadTodos();
110
+ }, []);
111
+
112
+ return <div>
113
+ <h1>My Todos</h1>
114
+ <TodoList todos={todos} />
115
+ </div>;
116
+ }
117
+ }
118
+ ```
119
+
120
+ ---
121
+
122
+ ## 🧩 3. Creating Components
123
+
124
+ Components in Jac are functions that return JSX (JavaScript XML). They're similar to React components but written in pure Jac syntax.
125
+
126
+ ### Basic Component Structure
127
+
128
+ ```jac
129
+ cl {
130
+ def MyComponent() -> any {
131
+ return <div>
132
+ <h1>Hello from Jac!</h1>
133
+ </div>;
134
+ }
135
+ }
136
+ ```
137
+
138
+ ### Component with Props
139
+
140
+ Components can accept parameters (props):
141
+
142
+ ```jac
143
+ def TodoItem(item: dict) -> any {
144
+ return <li key={item.id}>
145
+ <span>{item.text}</span>
146
+ <button onClick={lambda -> None { removeTodo(item.id); }}>
147
+ Remove
148
+ </button>
149
+ </li>;
150
+ }
151
+ ```
152
+
153
+ **Component Features:**
154
+ - **JSX Syntax**: Write HTML-like syntax directly in Jac
155
+ - **Inline Styles**: Use JavaScript objects for styling
156
+ - **Event Handlers**: Attach functions to user interactions
157
+ - **Reusability**: Components can call other components
158
+
159
+ ### Example: TodoItem Component
160
+
161
+ ```jac
162
+ def TodoItem(item: dict) -> any {
163
+ return <li key={item.id} style={{
164
+ "display": "flex",
165
+ "gap": "12px",
166
+ "alignItems": "center",
167
+ "padding": "12px",
168
+ "background": "#FFFFFF",
169
+ "borderRadius": "10px"
170
+ }}>
171
+ <input
172
+ type="checkbox"
173
+ checked={item.done}
174
+ onChange={lambda -> None { toggleTodo(item.id); }}
175
+ />
176
+ <span style={{
177
+ "textDecoration": ("line-through" if item.done else "none")
178
+ }}>
179
+ {item.text}
180
+ </span>
181
+ <button onClick={lambda -> None { removeTodo(item.id); }}>
182
+ Remove
183
+ </button>
184
+ </li>;
185
+ }
186
+ ```
187
+
188
+ **Breaking it down:**
189
+ - `item: dict` - Component receives a dictionary (todo item) as a prop
190
+ - `style={{...}}` - Inline styles using JavaScript objects
191
+ - `checked={item.done}` - Dynamic attribute binding
192
+ - `onChange={lambda -> None {...}}` - Event handler using lambda
193
+ - `{item.text}` - Interpolation of JavaScript expressions in JSX
194
+
195
+ ---
196
+
197
+ ## 🗄️ 4. Adding State with React Hooks
198
+
199
+ Jac uses React hooks for state management. You can use all standard React hooks by importing them:
200
+
201
+ ```jac
202
+ cl import from react { useState, useEffect }
203
+
204
+ cl {
205
+ def Counter() -> any {
206
+ let [count, setCount] = useState(0);
207
+
208
+ useEffect(lambda -> None {
209
+ console.log("Count changed:", count);
210
+ }, [count]);
211
+
212
+ return <div>
213
+ <h1>Count: {count}</h1>
214
+ <button onClick={lambda e: any -> None {
215
+ setCount(count + 1);
216
+ }}>
217
+ Increment
218
+ </button>
219
+ </div>;
220
+ }
221
+ }
222
+ ```
223
+
224
+ **Available React Hooks:**
225
+ - `useState` - For state management
226
+ - `useEffect` - For side effects
227
+ - `useRef` - For refs
228
+ - `useContext` - For context
229
+ - `useCallback`, `useMemo` - For performance optimization
230
+ - And more...
231
+
232
+ ### State Management Example
233
+
234
+ Here's a complete example showing state management in a todo app:
235
+
236
+ ```jac
237
+ cl import from react {useState, useEffect}
238
+
239
+ cl {
240
+ def app() -> any {
241
+ let [todos, setTodos] = useState([]);
242
+ let [input, setInput] = useState("");
243
+ let [filter, setFilter] = useState("all");
244
+
245
+ # Load todos on mount
246
+ useEffect(lambda -> None {
247
+ async def loadTodos() -> None {
248
+ result = root spawn read_todos();
249
+ setTodos(result.reports if result.reports else []);
250
+ }
251
+ loadTodos();
252
+ }, []);
253
+
254
+ # Add new todo
255
+ async def addTodo() -> None {
256
+ if not input.trim() { return; }
257
+ response = root spawn create_todo(text=input.trim());
258
+ new_todo = response.reports[0][0];
259
+ setTodos(todos.concat([new_todo]));
260
+ setInput("");
261
+ }
262
+
263
+ # Filter todos
264
+ def getFilteredTodos() -> list {
265
+ if filter == "active" {
266
+ return todos.filter(lambda todo: any -> bool { return not todo.done; });
267
+ } elif filter == "completed" {
268
+ return todos.filter(lambda todo: any -> bool { return todo.done; });
269
+ }
270
+ return todos;
271
+ }
272
+
273
+ filteredTodos = getFilteredTodos();
274
+
275
+ return <div>
276
+ <h1>My Todos</h1>
277
+ <input
278
+ value={input}
279
+ onChange={lambda e: any -> None { setInput(e.target.value); }}
280
+ onKeyPress={lambda e: any -> None {
281
+ if e.key == "Enter" { addTodo(); }
282
+ }}
283
+ />
284
+ <button onClick={addTodo}>Add</button>
285
+
286
+ <div>
287
+ {filteredTodos.map(lambda todo: any -> any {
288
+ return <div key={todo._jac_id}>
289
+ <span>{todo.text}</span>
290
+ </div>;
291
+ })}
292
+ </div>
293
+ </div>;
294
+ }
295
+ }
296
+ ```
297
+
298
+ ---
299
+
300
+ ## 🎯 5. Event Handling
301
+
302
+ Event handling in Jac works just like React, but with Jac's lambda syntax.
303
+
304
+ ### Basic Event Handlers
305
+
306
+ ```jac
307
+ def Button() -> any {
308
+ return <button onClick={lambda -> None {
309
+ console.log("Button clicked!");
310
+ }}>
311
+ Click Me
312
+ </button>;
313
+ }
314
+ ```
315
+
316
+ ### Event Handlers with Event Object
317
+
318
+ ```jac
319
+ def InputField() -> any {
320
+ let [value, setValue] = useState("");
321
+
322
+ return <input
323
+ type="text"
324
+ value={value}
325
+ onChange={lambda e: any -> None {
326
+ console.log("Input value:", e.target.value);
327
+ setValue(e.target.value);
328
+ }}
329
+ />;
330
+ }
331
+ ```
332
+
333
+ ### Form Submission
334
+
335
+ ```jac
336
+ def TodoForm() -> any {
337
+ return <form onSubmit={onAddTodo}>
338
+ <input id="todo-input" type="text" />
339
+ <button type="submit">Add Todo</button>
340
+ </form>;
341
+ }
342
+
343
+ async def onAddTodo(e: any) -> None {
344
+ e.preventDefault(); # Prevent page refresh
345
+ inputEl = document.getElementById("todo-input");
346
+ text = inputEl.value.trim();
347
+
348
+ if not text { return; }
349
+
350
+ # Handle form submission
351
+ response = root spawn create_todo(text=text);
352
+ new_todo = response.reports[0][0];
353
+ # ... update state
354
+ }
355
+ ```
356
+
357
+ ### Common Event Types
358
+
359
+ | Event | Syntax | Use Case |
360
+ |-------|--------|----------|
361
+ | `onClick` | `onClick={lambda -> None {...}}` | Button clicks |
362
+ | `onChange` | `onChange={lambda e: any -> None {...}}` | Input changes |
363
+ | `onSubmit` | `onSubmit={lambda e: any -> None {...}}` | Form submission |
364
+ | `onKeyPress` | `onKeyPress={lambda e: any -> None {...}}` | Keyboard input |
365
+
366
+ ### Advanced: Conditional Event Handlers
367
+
368
+ ```jac
369
+ def FilterButton(filterType: str, currentFilter: str, onFilterChange: any) -> any {
370
+ isActive = currentFilter == filterType;
371
+
372
+ return <button
373
+ onClick={lambda -> None {
374
+ onFilterChange(filterType);
375
+ }}
376
+ style={{
377
+ "background": ("#7C3AED" if isActive else "#FFFFFF"),
378
+ "color": ("#FFFFFF" if isActive else "#7C3AED")
379
+ }}
380
+ >
381
+ {filterType}
382
+ </button>;
383
+ }
384
+ ```
385
+
386
+ ---
387
+
388
+ ## ✨ 6. Magic: No More Axios/Fetch!
389
+
390
+ One of Jac's most powerful features is **seamless backend communication** without writing HTTP requests, fetch calls, or axios code.
391
+
392
+ ### The `spawn` Syntax
393
+
394
+ Instead of writing:
395
+ ```javascript
396
+ // Traditional approach
397
+ const response = await fetch('/api/todos', {
398
+ method: 'POST',
399
+ headers: { 'Content-Type': 'application/json' },
400
+ body: JSON.stringify({ text: 'New todo' })
401
+ });
402
+ const data = await response.json();
403
+ ```
404
+
405
+ You simply write:
406
+ ```jac
407
+ response = root spawn create_todo(text="New todo");
408
+ ```
409
+
410
+ ### How `spawn` Works
411
+
412
+ ```jac
413
+ # Call a walker on a node
414
+ result = node_reference spawn walker_name(parameters);
415
+ ```
416
+
417
+ **Syntax:**
418
+ - `node_reference` - The node to spawn the walker on (commonly `root` for the root node, or a node ID)
419
+ - `spawn` - The spawn keyword
420
+ - `walker_name` - Name of the walker to execute
421
+ - `parameters` - Parameters to pass to the walker (as function arguments)
422
+
423
+ **Example from Todo App:**
424
+ ```jac
425
+ # Create a new todo (spawn on root node)
426
+ response = root spawn create_todo(text=text);
427
+
428
+ # Toggle todo status (spawn on specific todo node)
429
+ id spawn toggle_todo();
430
+
431
+ # Read all todos
432
+ todos = root spawn read_todos();
433
+ ```
434
+
435
+ ### Backend Walkers
436
+
437
+ Walkers are defined in the same `app.jac` file (outside the `cl` block):
438
+
439
+ ```jac
440
+ # Node definition (data model)
441
+ node Todo {
442
+ has text: str;
443
+ has done: bool = False;
444
+ }
445
+
446
+ # Walker: Create a new todo
447
+ walker create_todo {
448
+ has text: str;
449
+ can create with `root entry {
450
+ new_todo = here ++> Todo(text=self.text);
451
+ report new_todo;
452
+ }
453
+ }
454
+
455
+ # Walker: Toggle todo status
456
+ walker toggle_todo {
457
+ can toggle with Todo entry {
458
+ here.done = not here.done;
459
+ report here;
460
+ }
461
+ }
462
+
463
+ # Walker: Read all todos
464
+ walker read_todos {
465
+ can read with `root entry {
466
+ visit [-->(`?Todo)];
467
+ }
468
+
469
+ can report_todos with exit {
470
+ report here;
471
+ }
472
+ }
473
+ ```
474
+
475
+ ### Complete Example: Creating a Todo
476
+
477
+ **Frontend (in `cl` block):**
478
+ ```jac
479
+ async def onAddTodo(e: any) -> None {
480
+ e.preventDefault();
481
+ text = document.getElementById("todo-input").value.trim();
482
+ if not text { return; }
483
+
484
+ # Call backend walker - no fetch/axios needed!
485
+ response = root spawn create_todo(text=text);
486
+ new_todo = response.reports[0][0];
487
+
488
+ # Update frontend state
489
+ s = todoState();
490
+ newItem = {
491
+ "id": new_todo._jac_id,
492
+ "text": new_todo.text,
493
+ "done": new_todo.done
494
+ };
495
+ setTodoState({"items": s.items.concat([newItem])});
496
+ }
497
+ ```
498
+
499
+ **Backend (outside `cl` block):**
500
+ ```jac
501
+ walker create_todo {
502
+ has text: str;
503
+ can create with `root entry {
504
+ # 'text' comes from the walker parameter
505
+ new_todo = here ++> Todo(text=self.text);
506
+ report new_todo;
507
+ }
508
+ }
509
+ ```
510
+
511
+ ### Benefits of `spawn`
512
+
513
+ ✅ **No HTTP Configuration**: No need to set up API endpoints, CORS, or request/response formats
514
+ ✅ **Type Safety**: Jac handles serialization automatically
515
+ ✅ **Authentication**: Built-in token management via `jacLogin()` / `jacLogout()`
516
+ ✅ **Error Handling**: Exceptions are properly propagated
517
+ ✅ **Graph Operations**: Direct access to graph-based data operations
518
+ ✅ **Less Code**: Eliminates boilerplate HTTP client code
519
+ ✅ **Natural Syntax**: Call walkers on nodes using intuitive syntax
520
+
521
+ ### Authentication Helpers
522
+
523
+ Jac also provides built-in auth functions:
524
+
525
+ ```jac
526
+ # Sign up
527
+ result = await jacSignup(username, password);
528
+ if result["success"] {
529
+ navigate("/todos");
530
+ }
531
+
532
+ # Log in
533
+ success = await jacLogin(username, password);
534
+ if success {
535
+ navigate("/todos");
536
+ }
537
+
538
+ # Log out
539
+ jacLogout();
540
+ navigate("/login");
541
+
542
+ # Check if logged in
543
+ if jacIsLoggedIn() {
544
+ return <div>Welcome!</div>;
545
+ }
546
+ ```
547
+
548
+ ---
549
+
550
+ ## 🎨 Complete Example: Todo App Structure
551
+
552
+ Here's how all the pieces fit together:
553
+
554
+ ```jac
555
+ # ============================================================================
556
+ # BACKEND: Data Models and Walkers
557
+ # ============================================================================
558
+ node Todo {
559
+ has text: str;
560
+ has done: bool = False;
561
+ }
562
+
563
+ walker create_todo {
564
+ has text: str;
565
+ can create with `root entry {
566
+ new_todo = here ++> Todo(text=self.text);
567
+ report new_todo;
568
+ }
569
+ }
570
+
571
+ # ============================================================================
572
+ # FRONTEND: Components, State, and Events
573
+ # ============================================================================
574
+ cl import from react {useState}
575
+
576
+ cl {
577
+ def app() -> any {
578
+ let [todos, setTodos] = useState([]);
579
+ let [input, setInput] = useState("");
580
+
581
+ # Event Handler
582
+ async def addTodo() -> None {
583
+ if not input.trim() { return; }
584
+ response = root spawn create_todo(text=input.trim());
585
+ new_todo = response.reports[0][0];
586
+ setTodos(todos.concat([new_todo]));
587
+ setInput("");
588
+ }
589
+
590
+ return <div>
591
+ <h2>My Todos</h2>
592
+ <input
593
+ value={input}
594
+ onChange={lambda e: any -> None { setInput(e.target.value); }}
595
+ onKeyPress={lambda e: any -> None {
596
+ if e.key == "Enter" { addTodo(); }
597
+ }}
598
+ />
599
+ <button onClick={addTodo}>Add Todo</button>
600
+
601
+ <div>
602
+ {todos.map(lambda todo: any -> any {
603
+ return <div key={todo._jac_id}>
604
+ <span>{todo.text}</span>
605
+ </div>;
606
+ })}
607
+ </div>
608
+ </div>;
609
+ }
610
+ }
611
+ ```
612
+
613
+ ---
614
+
615
+ ## 🚀 Running the Todo App
616
+
617
+ To run this example:
618
+
619
+ ```bash
620
+ # From the todo-app directory
621
+ jac serve app.jac
622
+ ```
623
+
624
+ Then visit `http://localhost:8000` in your browser.
625
+
626
+ ---
627
+
628
+ ## 📚 Next Steps
629
+
630
+ Ready to dive deeper? Explore these advanced topics:
631
+
632
+ - **[Routing](routing.md)**: Build multi-page apps with declarative routing (`<Router>`, `<Routes>`, `<Route>`)
633
+ - **[Lifecycle Hooks](lifecycle-hooks.md)**: Use `onMount()` and React hooks for initialization logic
634
+ - **[Advanced State](advanced-state.md)**: Manage complex state with React hooks and context
635
+ - **[Imports](imports.md)**: Import third-party libraries (React, Ant Design, Lodash), other Jac files, and JavaScript modules
636
+ - **[Learn JAC](https://www.jac-lang.org)**: Explore Jac's graph-based data modeling
637
+
638
+ ## 🎓 Examples
639
+
640
+ Check out the `examples/` directory for working applications:
641
+
642
+ - **[basic](../../examples/basic/)**: Simple counter app using React hooks
643
+ - **[with-router](../../examples/with-router/)**: Multi-page app with declarative routing
644
+ - **[little-x](../../examples/little-x/)**: Social media app with third-party libraries
645
+ - **[todo-app](../../examples/todo-app/)**: Full-featured todo app with authentication
646
+ - **[basic-full-stack](../../examples/basic-full-stack/)**: Full-stack app with backend integration
647
+
648
+ ---
649
+
650
+ ## 💡 Key Takeaways
651
+
652
+ 1. **Single Language**: Write frontend and backend in Jac
653
+ 2. **No HTTP Client**: Use `spawn` syntax instead of fetch/axios
654
+ 3. **Reactive State**: React hooks manage UI updates automatically
655
+ 4. **Component-Based**: Build reusable UI components with JSX
656
+ 5. **Type Safety**: Jac provides type checking across frontend and backend
657
+ 6. **Graph Database**: Built-in graph data model eliminates need for SQL/NoSQL
658
+
659
+ Happy coding with Jac! 🎉