UNPKG

lightview

Version:

A reactive UI library with features of Bau, Juris, and HTMX plus safe LLM UI generation

167 lines (140 loc) 5.51 kB
<!-- SEO-friendly SPA Shim --> <script src="/lightview-router.js?base=/index.html"></script> <div class="docs-layout"> <aside class="docs-sidebar" src="./nav.html" data-preserve-scroll="docs-nav"></aside> <main class="docs-content"> <h1>Effects</h1> <p> Effects let you run side effects when reactive state changes. Logging, DOM manipulation, API calls—anything that needs to happen <em>because</em> something changed. </p> <h2>Basic Usage</h2> <pre><code>const { signal, effect } = Lightview; const count = signal(0); // This runs immediately, then re-runs when count changes effect(() => { console.log('Count is now:', count.value); }); count.value = 1; // Logs: "Count is now: 1" count.value = 2; // Logs: "Count is now: 2"</code></pre> <h2>Automatic Dependency Tracking</h2> <p> Effects automatically track which signals they read. No need to declare dependencies—Lightview figures it out: </p> <pre><code>const firstName = signal('Alice'); const lastName = signal('Smith'); const showFull = signal(true); effect(() => { if (showFull.value) { // Tracks firstName, lastName, and showFull console.log(`${firstName.value} ${lastName.value}`); } else { // Only tracks firstName and showFull console.log(firstName.value); } });</code></pre> <h2>Stopping Effects</h2> <p> Effects return a stop function: </p> <pre><code>const count = signal(0); const stop = effect(() => { console.log('Count:', count.value); }); count.value = 1; // Logs count.value = 2; // Logs stop(); // Stop the effect count.value = 3; // Nothing logged</code></pre> <h2>Common Patterns</h2> <h3>Syncing to External Systems</h3> <pre><code>const theme = signal('light'); effect(() => { document.body.setAttribute('data-theme', theme.value); });</code></pre> <h3>Local Storage Persistence</h3> <pre><code>const settings = signal( JSON.parse(localStorage.getItem('settings')) || {} ); effect(() => { localStorage.setItem('settings', JSON.stringify(settings.value)); });</code></pre> <h3>API Calls</h3> <pre><code>const userId = signal(1); const userData = signal(null); effect(async () => { const id = userId.value; const response = await fetch(`/api/users/${id}`); userData.value = await response.json(); });</code></pre> <h2>Effects vs Computed</h2> <table class="api-table"> <thead> <tr> <th>Use Case</th> <th>Use This</th> </tr> </thead> <tbody> <tr> <td>Derive a value from signals</td> <td><code>computed()</code></td> </tr> <tr> <td>Side effects (logging, API calls, DOM)</td> <td><code>effect()</code></td> </tr> <tr> <td>Value needed in UI</td> <td><code>computed()</code></td> </tr> <tr> <td>Just need to "do something"</td> <td><code>effect()</code></td> </tr> </tbody> </table> <div class="code-example"> <div class="code-example-preview" id="effect-demo"></div> <div class="code-example-code"> <pre><code>const name = signal('World'); const log = signal([]); effect(() => { log.value = [...log.value, `Hello, ${name.value}!`].slice(-5); }); // Change name to see the effect in action</code></pre> </div> </div> </main> </div> <script> (function () { const { signal, effect, tags } = Lightview; const { div, p, input, ul, li, label } = tags; const name = signal('World'); const log = signal([]); effect(() => { const entry = `${new Date().toLocaleTimeString()} - Hello, ${name.value}!`; log.value = [...log.value, entry].slice(-5); }); const demo = div({ style: 'padding: 0.5rem;' }, div({ style: 'margin-bottom: 1rem;' }, label({ style: 'display: block; margin-bottom: 0.25rem; font-size: 0.875rem; color: var(--site-text-secondary);' }, 'Change name to trigger effect:'), input({ type: 'text', value: name.value, oninput: (e) => name.value = e.target.value, style: 'padding: 0.5rem; border: 1px solid var(--site-border); border-radius: 4px; width: 200px;' }) ), div( p({ style: 'font-size: 0.875rem; color: var(--site-text-secondary); margin: 0 0 0.5rem;' }, 'Effect log (last 5):'), ul({ style: 'margin: 0; padding-left: 1.25rem; font-family: var(--site-font-mono); font-size: 0.8125rem;' }, () => log.value.map(entry => li(entry)) ) ) ); const container = document.getElementById('effect-demo'); if (container) container.appendChild(demo.domEl); })(); </script>