### Install signal-utils and signal-polyfill Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Installs the necessary packages for using signal-utils and its polyfill. This command adds both 'signal-utils' and 'signal-polyfill' to your project's dependencies. ```bash npm add signal-utils signal-polyfill ``` -------------------------------- ### Install Dependencies with pnpm Source: https://github.com/proposal-signals/signal-utils/blob/main/CONTRIBUTING.md Installs all necessary project dependencies using the pnpm package manager. This is a prerequisite for developing and testing the project. ```bash pnpm install ``` -------------------------------- ### Start Build and Tests in Watch Mode with concurrently Source: https://github.com/proposal-signals/signal-utils/blob/main/CONTRIBUTING.md Initiates a concurrent build process using pnpm start, which runs both the Vite build and Vitest tests in parallel. This is useful for debugging the build process or preparing for releases. ```bash pnpm start ``` -------------------------------- ### JavaScript localCopy for Two-Way Binding Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Demonstrates using the `localCopy` function to create a mutable local signal that mirrors a read-only remote signal. It includes an example of updating the local signal from an input event, suitable for controlled input elements. ```javascript import { Signal } from 'signal-polyfill'; import { localCopy } from 'signal-utils/local-copy'; const remote = new Signal.State(3); const local = localCopy(() => remote.get()); const updateLocal = (inputEvent) => local.set(inputEvent.target.value); // A controlled input ``` -------------------------------- ### Run Vitest Tests in Watch Mode Source: https://github.com/proposal-signals/signal-utils/blob/main/CONTRIBUTING.md Starts the Vitest test runner in watch mode, automatically re-running tests when source files change. This is the primary method for developing and unit testing within the package. ```bash pnpm vitest --watch ``` -------------------------------- ### Create signals with @signal decorator Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Demonstrates the use of the '@signal' decorator to create reactive signals within a class. It shows how to define a signal accessor and a computed property that depends on it, along with a method to update the signal's value. This example is suitable for frameworks like Glimmer or Svelte. ```jsx import { signal } from 'signal-utils'; class State { @signal accessor #value = 3; get doubled() { return this.#value * 2; } increment = () => this.#value++; } let state = new State(); // output: 6 // button clicked // output: 8 ``` -------------------------------- ### Deep reactivity with @deepSignal decorator Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Shows how to use the '@deepSignal' decorator for recursive, deep, and lazy auto-tracking of JSON-serializable structures. This allows for reactivity at any depth within objects and arrays. The example demonstrates updating nested properties and incrementing a value within a deeply nested structure. ```gjs import { deepSignal } from 'signal-utils/deep'; class Foo { @deepSignal accessor obj = {}; } let instance = new Foo(); let setData = () => instance.obj.foo = { bar: 3 }; let inc = () => instance.obj.foo.bar++; ``` -------------------------------- ### Cache getters with @signal decorator Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Illustrates using the '@signal' decorator to cache the results of a getter method within a class. This is useful for expensive computations, especially when returning non-primitive values to maintain referential integrity. The example shows a 'doubled' getter that is cached. ```js import { signal } from 'signal-utils'; class State { @signal accessor #value = 3; // NOTE: read-only because there is no setter, and a setter is not allowed. @signal get doubled() { // imagine an expensive operation return this.#value * 2; } increment = () => this.#value++; } let state = new State(); // output: 6 // button clicked // output: 8 ``` -------------------------------- ### Build the Package Source: https://github.com/proposal-signals/signal-utils/blob/main/CONTRIBUTING.md Executes the build process for the package using the pnpm build command. This is a required step before preparing a Pull Request to ensure the package is correctly built. ```bash pnpm build ``` -------------------------------- ### Construct Reactive Object with SignalObject.fromEntries and signalObject (JSX) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Demonstrates alternative ways to construct reactive objects using SignalObject.fromEntries and the signalObject factory function, offering different initialization patterns. ```jsx import { SignalObject, signalObject } from 'signal-utils/object'; SignalObject.fromEntries([ /* ... */ ]); signalObject({ /* ... */ } ); ``` -------------------------------- ### Simplified Reactive Promise Handling with load utility (JavaScript) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Shows a more concise way to handle reactive Promises using the `load` utility function from `signal-utils/async-data`. This function simplifies the creation of SignalAsyncData instances. ```js import { load } from 'signal-utils/async-data'; const response = fetch('...'); const signalResponse = load(response); // output: true // after the fetch finishes // output: false ``` -------------------------------- ### Create and Manipulate Reactive Map with SignalMap (JavaScript) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Illustrates the creation and usage of a reactive Map with SignalMap. This allows for reactive key-value storage, where changes to map entries trigger updates. ```js import { SignalMap } from 'signal-utils/map'; let map = new SignalMap(); map.set('isLoading', true); // output: true // button clicked // output: false ``` -------------------------------- ### Run All Tests with pnpm test Source: https://github.com/proposal-signals/signal-utils/blob/main/CONTRIBUTING.md Executes all project tests using the pnpm test command. This ensures that all tests pass before preparing a Pull Request. ```bash pnpm test ``` -------------------------------- ### Construct Reactive Array with SignalArray.from and signalArray (JSX) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Illustrates alternative methods for creating reactive arrays using SignalArray.from and the signalArray factory function. These methods provide flexibility in initializing SignalArray instances. ```jsx import { SignalArray, signalArray } from 'signal-utils/array'; SignalArray.from([1, 2, 3]); signalArray([1, 2, 3]); ``` -------------------------------- ### Format Code with pnpm format Source: https://github.com/proposal-signals/signal-utils/blob/main/CONTRIBUTING.md Runs the code formatting tool to ensure consistent code style across the project. This command must be executed successfully before submitting a Pull Request. ```bash pnpm format ``` -------------------------------- ### Create and Manipulate Reactive Set with SignalSet (JavaScript) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Shows how to create and use a reactive Set with SignalSet. This allows for reactive storage of unique values, where adding or deleting elements triggers updates. ```js import { SignalSet } from 'signal-utils/set'; let set = new SignalSet(); set.add(123); // output: true // button clicked // output: false ``` -------------------------------- ### Create and Manipulate Reactive Object with SignalObject (JavaScript) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Shows how to create a reactive object using SignalObject. This is useful for managing object properties reactively, where changes to properties automatically update the UI. ```js import { SignalObject } from 'signal-utils/object'; let obj = new SignalObject({ isLoading: true, error: null, result: null, }); // output: true // button clicked // output: false ``` -------------------------------- ### Create and Manipulate Reactive WeakMap with SignalWeakMap (JavaScript) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Demonstrates creating a reactive WeakMap using SignalWeakMap. This provides a reactive way to store key-value pairs where keys are weakly held, suitable for scenarios where memory management is a concern. ```js import { SignalWeakMap } from 'signal-utils/weak-map'; let map = new SignalWeakMap(); let obj = { greeting: 'hello' }; map.set(obj, true); // output: true // button clicked // output: false ``` -------------------------------- ### Create and Manipulate Reactive Array with SignalArray (JSX) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Demonstrates creating a reactive array using SignalArray in JSX. It shows how to initialize, render array elements, and modify the array using methods like pop, which trigger UI updates. ```jsx import { SignalArray } from 'signal-utils/array'; let arr = new SignalArray([1, 2, 3]); // output: 3 // button clicked // output: 2 ``` -------------------------------- ### Handle Reactive Promises with SignalAsyncData (JavaScript) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Demonstrates using SignalAsyncData to manage the state of a Promise reactively. It provides properties like isLoading, error, and value to track the promise's lifecycle and update the UI accordingly. ```js import { SignalAsyncData } from 'signal-utils/async-data'; const response = fetch('...'); const signalResponse = new SignalAsyncData(response); // output: true // after the fetch finishes // output: false ``` -------------------------------- ### JavaScript localCopy for Two-Way Binding (Preact) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md An implementation of `localCopy` using Preact hooks, enabling synchronization between a local state and a remote signal. It handles updates from input events and demonstrates parent-child communication for data binding. ```javascript import { render } from 'preact'; import { useRef, useEffect } from 'preact/hooks'; import { signal, effect, useSignal } from '@preact/signals'; import { html } from 'html/preact'; function useLocalCopy(remote) { const local = useRef(); if (!local.current) { local.current = signal(remote.peek()); } useEffect(() => { // Synchronously update the local copy when remote changes. // Core effects are just a way to have synchronous callbacks // react to signal changes in a pretty efficient way. return effect(() => { local.current.value = remote.value; }); }, [remote]); return local.current; } function Demo({ name, onSubmit }) { const localName = useLocalCopy(name); const updateLocalName = (inputEvent) => localName.value = inputEvent.target.value; const handleSubmit = (submitEvent) => { submitEvent.preventDefault(); onSubmit({ value: localName.value }); } return html`
localValue: ${localName}
parent value: ${name}
` } export function App() { const name = useSignal('Mace Windu'); const data = useSignal(''); const handleSubmit = (d) => data.value = d; const changeName = () => name.value += '!'; return html` <${Demo} name=${name} onSubmit=${handleSubmit} />
Cause external change (maybe simulating a refresh of remote data):
Last Submitted:
${JSON.stringify(data.value, null, 3)}
` } render(, document.getElementById('app')); ``` -------------------------------- ### Create and Manipulate Reactive WeakSet with SignalWeakSet (JavaScript) Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Illustrates creating a reactive WeakSet using SignalWeakSet. This provides a reactive way to store unique objects that are weakly held, aiding in memory management. ```js import { SignalWeakSet } from 'signal-utils/weak-set'; let set = new SignalWeakSet(); let obj = { greeting: 'hello' }; set.add(obj); // output: true // button clicked // output: false ``` -------------------------------- ### Synchronous Batched Effects Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Provides utilities for running effects synchronously at the end of a batch of signal updates. `batchedEffect` and `batch` allow for predictable, synchronous reactions to signal changes within a controlled scope, useful for abstracting signal behavior. ```javascript const a = new Signal.State(0); const b = new Signal.State(0); batchedEffect(() => { console.log("a + b =", a.get() + b.get()); }); // Logs: a + b = 0 batch(() => { a.set(1); b.set(1); }); // Logs: a + b = 2 ``` -------------------------------- ### Reactive Async Function with Signal Handling Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Wraps an async function to provide reactive loading, error, and value states. It automatically tracks signal dependencies within the async function and manages the lifecycle of the asynchronous operation. Useful for fetching data based on signal changes. ```javascript import { Signal } from 'signal-polyfill'; import { signalFunction } from 'signal-utils/async-function'; const url = new Signal.State('...'); const signalResponse = signalFunction(async () => { const response = await fetch(url.get()); // entangles with `url` // after an away, you've detatched from the signal-auto-tracking return response.json(); }); // output: true // after the fetch finishes // output: false ``` -------------------------------- ### Reactive Reaction Handler Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Implements a reaction pattern that tracks signal dependencies in a computation and executes an effect function when the computed value changes. It logs the new and previous values after a microtask, providing insight into state transitions. ```javascript import { Signal } from 'signal-polyfill'; import { reaction } from 'signal-utils/subtle/reaction.js'; const a = new Signal.State(0); const b = new Signal.State(1); reaction( () => a.get() + b.get(), (value, previousValue) => console.log(value, previousValue) ); a.set(1); // after a microtask, logs: 2, 1 ``` -------------------------------- ### Leaky Effect via queueMicrotask Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Demonstrates a reactive effect that runs asynchronously after signal updates using `queueMicrotask`. This can lead to subtle bugs if not managed carefully, as the effect's execution is deferred. It logs the updated signal value after a microtask. ```javascript import { Signal } from 'signal-polyfill'; import { effect } from 'signal-utils/subtle/microtask-effect'; let count = new Signal.State(0); let callCount = 0; effect(() => console.log(count.get()); // => 0 logs count.set(1); // => 1 logs ``` -------------------------------- ### AsyncComputed API Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md The AsyncComputed API allows for managing asynchronous computations reactively. It provides properties to track the status, value, and errors of the computation, as well as methods to trigger and access the computation's results. ```APIDOC ## AsyncComputed API ### Description Provides a reactive way to manage asynchronous computations, including status tracking, value retrieval, and error handling. ### Constructor `constructor(fn, options)` - **fn** (`(abortSignal: AbortSignal) => Promise`) - Required - The asynchronous compute function. Synchronous signal access (before the first await) is tracked. If a run is preempted by another run due to dependency changes, the AbortSignal will be aborted. It's recommended to call `signal.throwIfAborted()` after any `await`. - **options** (`AsyncComputedOptions`) - Optional - Configuration options for AsyncComputed. - **initialValue** (`T`) - Optional - The initial value to return from `.value` before the computation has run. ### Properties - **status** (`"initial" | "pending" | "complete" | "error"`) - The current status of the computation. - **value** (`T | undefined`) - The last successfully resolved value of the compute function. `undefined` if the last run resulted in an error or if the function has not yet run. - **error** (`unknown`) - The last error thrown by the compute function, or `undefined` if the last run was successful or the function has not yet run. - **complete** (`Promise`) - A promise that resolves with the result of the compute function upon completion or rejects if an error occurs. If a new run starts before the previous one completes, this promise will resolve with the result of the new run. ### Methods - **run()**: `void` - Initiates the computation if it's not already running and its dependencies have changed. - **get()**: `T | undefined` - Returns the current `value`. Throws an error if the last computation resulted in an error. Best used for accessing from other computed signals as it propagates error states. ### Request Example ```javascript const myComputed = new AsyncComputed(async (signal) => { const response = await fetch('/api/data', { signal }); signal.throwIfAborted(); // Good practice after await return await response.json(); }, { initialValue: null }); console.log(myComputed.status); // 'initial' or 'pending' console.log(myComputed.value); // null initially, then the fetched data console.log(myComputed.error); // undefined or the error object myComputed.run(); // Manually trigger a run ``` ### Response #### Success Response (200) - (Implicit via `.value` and `.complete` promise) - **value** (`T`) - The resolved value from the compute function. #### Error Response - (Implicit via `.error` and `.complete` promise rejection) - **error** (`unknown`) - The error thrown by the compute function. ### Response Example ```javascript // Example of accessing value after completion myComputed.complete.then(data => { console.log('Computation complete:', data); }); // Example of handling errors myComputed.complete.catch(err => { console.error('Computation failed:', err); }); ``` ``` -------------------------------- ### Deep Auto-Tracking with `deep` in Glimmer Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md The `deep` function from signal-utils enables recursive and lazy auto-tracking of JSON-serializable structures. It can handle nested objects and arrays at any depth. Be mindful of potential memory consumption and the increased difficulty in inspecting nested proxies. ```gjs import { deep } from 'signal-utils/deep'; let obj = deep({}); let setData = () => obj.foo = { bar: 3 }; let inc = () => obj.foo.bar++; ``` -------------------------------- ### AsyncComputed for Asynchronous Computations Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md Represents an asynchronous computation that depends on other signals. `AsyncComputed` reruns its async function when dependencies change, preempting previous runs. It manages states like 'initial', 'pending', 'complete', and 'error', and provides a `.complete` promise for awaiting results. ```typescript import {AsyncComputed} from 'signal-utils/async-computed'; const count = new Signal.State(1); const asyncDoubled = new AsyncComputed(async () => { // Wait 10ms await new Promise((res) => setTimeout(res, 10)); return count.get() * 2; }); console.log(asyncDoubled.status); // Logs: pending console.log(asyncDoubled.value); // Logs: undefined await asyncDoubled.complete; console.log(asyncDoubled.status); // Logs: complete console.log(asyncDoubled.value); // Logs: 2 ``` -------------------------------- ### Local State Management with `@localCopy` in Glimmer Source: https://github.com/proposal-signals/signal-utils/blob/main/README.md The `@localCopy` decorator from signal-utils is designed for maintaining local state that synchronizes with a remote value. It's particularly useful for editable fields where initial data comes from a remote source and might also change dynamically. The local state will reset to the remote value if the remote value is updated. ```gjs import { signal } from 'signal-utils'; import { localCopy } from 'signal-utils/local-copy'; class Remote { @signal accessor value = 3; } class Demo { // pretend this data is from a parent component remote = new Remote(); @localCopy('remote.value') localValue; updateLocalValue = (inputEvent) => this.localValue = inputEvent.target.value; // A controlled input } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.