|
| 1 | +# Lifecycle |
| 2 | + |
| 3 | +Understanding the lifecycle of an Entity and its Shadow Objects is crucial for managing resources, side effects, and subscriptions correctly. |
| 4 | + |
| 5 | +## The Entity Lifecycle |
| 6 | + |
| 7 | +An Entity's life is controlled by the **ViewComponent API**. |
| 8 | + |
| 9 | +### View Components & Component Context |
| 10 | + |
| 11 | +The underlying machinery involves two key classes: |
| 12 | +1. **`ViewComponent`**: Represents a single node in the View Layer. |
| 13 | +2. **`ComponentContext`**: Orchestrates a group of ViewComponents, manages their hierarchy, and batches changes (Change Trails) to be sent to the Kernel. |
| 14 | + |
| 15 | +While most developers use the provided Web Components, it's helpful to understand how they map to this API: |
| 16 | + |
| 17 | +* **`<shae-ent>` (The Entity):** When this Web Component is connected to the DOM, it internally creates a new `ViewComponent` instance and mounts it. |
| 18 | +* **`<shae-worker>` (The Environment):** This Web Component (or similar environment wrappers) manages the `ComponentContext`. It ensures that all `<shae-ent>` children are registered within the same context, allowing them to form a cohesive tree structure that is then synced to the Shadow World. |
| 19 | + |
| 20 | +### Lifecycle Phases |
| 21 | + |
| 22 | +1. **Mount (View Layer):** The View Component is initialized and registered with its Context. |
| 23 | + * *Web Components:* `<shae-ent>` connects, finds its nearest `ComponentContext` (provided by parent `<shae-ent>` or root `<shae-worker>`), and registers itself. |
| 24 | + * *Manual:* You create a `ViewComponent` and call `context.addComponent(component)`. |
| 25 | +2. **Creation (Shadow):** The `ComponentContext` sends a message to the Kernel describing the new component. The Kernel creates an `Entity` node. |
| 26 | +3. **Instantiation:** The Kernel resolves the Token and creates the associated Shadow Object(s). |
| 27 | +4. **Active:** The Shadow Object runs its logic, sets up signals, and reacts to changes. |
| 28 | +5. **Unmount (View Layer):** The View Component is disposed. |
| 29 | + * *Web Components:* `<shae-ent>` disconnects and calls `component.destroy()`. |
| 30 | + * *Manual:* You call `component.destroy()` or `context.destroyComponent(component)`. |
| 31 | +6. **Destruction (Shadow):** The Kernel destroys the `Entity` and triggers the cleanup of all associated Shadow Objects. |
| 32 | + |
| 33 | +## The Shadow Object Lifecycle |
| 34 | + |
| 35 | +Shadow Objects are functional units. Their lifecycle is simple: **Setup** and **Teardown**. |
| 36 | + |
| 37 | +### 1. Setup Phase (The Function Body) |
| 38 | +The code inside your function (or constructor) runs **once** when the object is instantiated. This is where you connect your logic to the framework. |
| 39 | + |
| 40 | +* **Goal:** Define your reactive graph. |
| 41 | +* **Actions (The ShadowObjectCreationAPI):** |
| 42 | + |
| 43 | + * **Inputs (Properties):** |
| 44 | + * `useProperty(name)`: Create a reactive signal for a single property. |
| 45 | + * `useProperties(map)`: Create signals for multiple properties at once. |
| 46 | + * **Context (Dependency Injection):** |
| 47 | + * `useContext(name)`: Consume a context value from the nearest ancestor provider. |
| 48 | + * `useParentContext(name)`: Consume a context value starting from the parent (skipping self). |
| 49 | + * `provideContext(name, value)`: Provide a value to descendants. |
| 50 | + * `provideGlobalContext(name, value)`: Provide a value globally to all entities. |
| 51 | + * **Reactivity:** |
| 52 | + * `createSignal(initial)`: Create a local state signal. |
| 53 | + * `createEffect(fn)`: Create a side effect that runs when dependencies change. |
| 54 | + * `createMemo(fn)`: Create a derived signal (computed value). |
| 55 | + * `createResource(factory, cleanup)`: Manage an external resource (like a 3D object) with lifecycle management. |
| 56 | + * **Events:** |
| 57 | + * `on(target, event, callback)`: Listen for events (from View or other objects). |
| 58 | + * `once(target, event, callback)`: Listen for an event exactly once. |
| 59 | + * **Lifecycle:** |
| 60 | + * `onDestroy(callback)`: Register a cleanup function to run when the object is destroyed. |
| 61 | + * **Access:** |
| 62 | + * `entity`: Direct access to the underlying `EntityApi` (advanced usage). |
| 63 | + |
| 64 | +```typescript |
| 65 | +export function MyLogic({ |
| 66 | + useProperty, |
| 67 | + createEffect, |
| 68 | + createSignal, |
| 69 | + on, |
| 70 | + entity, // Access to the entity instance |
| 71 | + onDestroy |
| 72 | +}) { |
| 73 | + // SETUP: Runs once |
| 74 | + const title = useProperty('title'); |
| 75 | + const [count, setCount] = createSignal(0); |
| 76 | + |
| 77 | + createEffect(() => { |
| 78 | + // RUNTIME: Runs whenever 'title' or 'count' changes |
| 79 | + console.log(`Title: ${title()}, Count: ${count()}`); |
| 80 | + }); |
| 81 | + |
| 82 | + // SETUP: Listen for View events |
| 83 | + // Events dispatched from the View are received on the entity instance as 'onViewEvent'. |
| 84 | + // The first argument is the type (name) of the event, the second is the data. |
| 85 | + on(entity, 'onViewEvent', (type, data) => { |
| 86 | + if (type === 'click') { |
| 87 | + setCount(c => c + 1); |
| 88 | + console.log('View was clicked!', data); |
| 89 | + } |
| 90 | + }); |
| 91 | + |
| 92 | + onDestroy(() => { |
| 93 | + // TEARDOWN: Runs once when destroyed |
| 94 | + console.log('Cleaning up...'); |
| 95 | + }); |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +### 2. Runtime Phase (Reactivity & Events) |
| 100 | +After setup, the Shadow Object is "alive". It doesn't re-run the main function. Instead, it reacts to changes in the environment. |
| 101 | + |
| 102 | +#### A. Reactive Updates |
| 103 | +Effects and Computed values (Memos) re-run whenever their dependencies change. |
| 104 | +* **Drivers:** Property updates (from View), Context updates (from Parent), or internal Signal changes. |
| 105 | + |
| 106 | +#### B. Event Flow |
| 107 | +The Runtime phase is also driven by **Events**, which can flow in multiple directions: |
| 108 | + |
| 109 | +1. **View → Entity:** The View Layer triggers standard DOM events (like `click`, `input`) or custom events. These are sent to the Entity as events. |
| 110 | + * **Mechanism:** The `ViewComponent` captures the DOM event and sends a message to the Shadow World. |
| 111 | + * **Reaction:** The Shadow Object listens to these events on the `entity` instance using `on(entity, 'onViewEvent', (type, data) => ... )`. The specific event name (e.g., 'click') is passed as the first argument. |
| 112 | +2. **Entity → View:** The Shadow Object can emit events. The View Layer receives these messages and can trigger UI updates (e.g., navigation, playing sound). |
| 113 | +3. **Entity Tree (Inter-Object):** Shadow Objects can communicate with each other via events. Because Entities form a tree, events can be dispatched through the hierarchy, allowing decoupled communication between logic units (e.g. a child item signaling a selection to a parent list). |
| 114 | + |
| 115 | +### 3. Teardown Phase (Cleanup) |
| 116 | +When the Entity is destroyed (or if the specific route that created this object is disabled), the Teardown phase begins. |
| 117 | + |
| 118 | +* **Automatic:** All framework-managed signals, effects, and event listeners (`createEffect`, `on`) are automatically disposed of. |
| 119 | +* **Manual:** Use `onDestroy` to clean up *external* resources, such as: |
| 120 | + * `setInterval` / `setTimeout` |
| 121 | + * Global event listeners (e.g. on `window`) |
| 122 | + * WebSockets or network connections |
| 123 | + |
| 124 | +> [!WARNING] |
| 125 | +> **Memory Leaks:** Always ensure you clean up non-framework resources in `onDestroy`. Failing to clear a `setInterval` will keep the closure alive indefinitely! |
0 commit comments