This commit is contained in:
@@ -1,21 +1,22 @@
|
||||
# Reactivity Control: `Watch( )`
|
||||
# Reactivity Control: `watch( )`
|
||||
|
||||
The `Watch` function is the reactive engine of SigPro. It allows you to execute code automatically when signals change. `Watch` is **polymorphic**: it can track dependencies automatically or follow an explicit list.
|
||||
The `watch` function is the reactive engine of SigPro. It allows you to execute code automatically when signals change. `watch` is **polymorphic**: it can track dependencies automatically or follow an explicit list.
|
||||
|
||||
## Function Signature
|
||||
|
||||
```typescript
|
||||
// Automatic Mode (Magic Tracking)
|
||||
Watch(callback: Function): StopFunction
|
||||
watch(callback: Function): StopFunction
|
||||
|
||||
// Explicit Mode (Isolated Dependencies)
|
||||
Watch(deps: Signal[], callback: Function): StopFunction
|
||||
watch(deps: Signal[], callback: (values: any[]) => void): StopFunction
|
||||
```
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **`target / deps`** | `Function` | `Array` | Yes | Either the code to run (Auto) or an array of signals to watch (Explicit). |
|
||||
| **`callback`** | `Function` | Only in Explicit | The code that will run when the `deps` change. |
|
||||
| **`callback`** (auto mode) | `Function` | Yes | The code to run. Any signal accessed inside becomes a dependency. |
|
||||
| **`deps`** (explicit mode) | `Signal[]` | Yes | An array of signals to watch explicitly. |
|
||||
| **`callback`** (explicit mode) | `Function` | Yes | Runs when any of the `deps` change. Receives an array of their current values. |
|
||||
|
||||
**Returns:** A `StopFunction` that, when called, destroys the watcher and releases memory.
|
||||
|
||||
@@ -24,68 +25,99 @@ Watch(deps: Signal[], callback: Function): StopFunction
|
||||
## Usage Patterns
|
||||
|
||||
### 1. Automatic Mode (Default)
|
||||
Any signal you "touch" inside the callback becomes a dependency. SigPro tracks them behind the scenes.
|
||||
Any signal you **touch** inside the callback becomes a dependency. SigPro tracks them behind the scenes.
|
||||
|
||||
```javascript
|
||||
const count = $(0);
|
||||
|
||||
Watch(() => {
|
||||
// Re-runs every time 'count' changes
|
||||
watch(() => {
|
||||
// Re‑runs every time 'count' changes
|
||||
console.log(`Count is: ${count()}`);
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Explicit Mode (Advanced Cleanup)
|
||||
This mode **isolates** execution. The callback only triggers when the signals in the array change. Any other signal accessed *inside* the callback will NOT trigger a re-run. This is the "gold standard" for Routers and heavy components.
|
||||
### 2. Explicit Mode (Isolated)
|
||||
This mode **isolates** execution. The callback only triggers when the signals in the array change. Any other signal accessed *inside* the callback will **not** trigger a re‑run. This is ideal for routers or performance‑critical components.
|
||||
|
||||
```javascript
|
||||
const sPath = $("/home");
|
||||
const path = $("/home");
|
||||
const user = $("Admin");
|
||||
|
||||
Watch([sPath], () => {
|
||||
// Only triggers when 'sPath' changes.
|
||||
// Changes to 'user' will NOT trigger this, preventing accidental re-renders.
|
||||
console.log(`Navigating to ${sPath()} as ${user()}`);
|
||||
watch([path], ([newPath]) => {
|
||||
// Only triggers when 'path' changes.
|
||||
// Changes to 'user' will NOT trigger this.
|
||||
console.log(`Navigating to ${newPath} as ${user()}`);
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Automatic Cleanup
|
||||
If your logic creates timers, event listeners, or other reactive effects, SigPro tracks them as "children" of the current watch. When the watcher re-runs or stops, it kills everything inside automatically.
|
||||
In explicit mode, the callback receives an array of current values corresponding to the `deps` order.
|
||||
|
||||
### 3. Stopping a Watcher
|
||||
Call the returned function to kill the watcher manually.
|
||||
|
||||
```javascript
|
||||
Watch(() => {
|
||||
const timer = setInterval(() => console.log("Tick"), 1000);
|
||||
|
||||
// Register a manual cleanup if needed
|
||||
// Or simply rely on SigPro to kill nested Watch() calls
|
||||
return () => clearInterval(timer);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stopping a Watcher
|
||||
Call the returned function to manually kill the watcher. This is essential for manual DOM injections (like Toasts) or long-lived background processes.
|
||||
|
||||
```javascript
|
||||
const stop = Watch(() => console.log(count()));
|
||||
|
||||
const stop = watch(() => console.log(count()));
|
||||
// Later...
|
||||
stop(); // The link between the signal and this code is physically severed.
|
||||
stop(); // Disconnects the watcher completely.
|
||||
```
|
||||
|
||||
### 4. Automatic Cleanup Inside Effects
|
||||
If your watcher creates timers, event listeners, or nested effects, SigPro tracks them as children and cleans them up automatically before re‑running or when stopped.
|
||||
|
||||
```javascript
|
||||
watch(() => {
|
||||
const timer = setInterval(() => console.log("tick"), 1000);
|
||||
// No need to manually clear – SigPro will dispose it when the watcher re‑runs or stops.
|
||||
// (But you can also return a cleanup function if needed)
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pro Tip: The Microtask Queue
|
||||
SigPro batches updates. If you update multiple signals in the same execution block, the watcher will only fire **once** at the end of the task.
|
||||
## Batching & Microtask Queue
|
||||
|
||||
SigPro batches reactive updates. If you modify several signals in the same synchronous block, the watcher will fire **only once**, after the task completes.
|
||||
|
||||
```javascript
|
||||
const a = $(0);
|
||||
const b = $(0);
|
||||
|
||||
Watch(() => console.log(a(), b()));
|
||||
watch(() => console.log(a(), b()));
|
||||
|
||||
// This triggers only ONE re-run.
|
||||
// Triggers only ONE log: "1 2"
|
||||
a(1);
|
||||
b(2);
|
||||
```
|
||||
|
||||
This is achieved via `queueMicrotask`, ensuring optimal performance.
|
||||
|
||||
---
|
||||
|
||||
## Key Points
|
||||
|
||||
- **Function name:** `watch` (lowercase) – exported from SigPro and also available globally.
|
||||
- **Auto mode:** `watch(fn)` – automatically tracks any signals read inside `fn`.
|
||||
- **Explicit mode:** `watch([sig1, sig2], (values) => {...})` – only re‑runs when listed signals change; callback receives an array of their new values.
|
||||
- **Stop function:** returned by both modes; call it to dispose the effect and its children.
|
||||
- **Batching:** multiple signal writes in one event loop tick trigger a single execution (microtask).
|
||||
|
||||
---
|
||||
|
||||
## Complete Example
|
||||
|
||||
```javascript
|
||||
const count = $(0);
|
||||
const step = $(1);
|
||||
|
||||
watch(() => {
|
||||
console.log(`Count changed to ${count()}`);
|
||||
});
|
||||
|
||||
watch([count, step], ([newCount, newStep]) => {
|
||||
console.log(`Count=${newCount}, step=${newStep} (explicit)`);
|
||||
});
|
||||
|
||||
count(5); // logs: auto + explicit
|
||||
step(2); // logs: explicit only (auto does not track step)
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user