From 1767d5777f631607d7fb40802e7524b8a9309eea Mon Sep 17 00:00:00 2001 From: Joachim Viide Date: Fri, 15 Mar 2024 15:58:54 +0000 Subject: [PATCH 1/3] docs: add comments explaining why prototypes are used instead of classes --- packages/core/src/index.ts | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 8d8978659..44959dc4d 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -193,7 +193,13 @@ function addDependency(signal: Signal): Node | undefined { return undefined; } -// @ts-ignore internal Signal is viewed as a function +// @ts-ignore: "Cannot redeclare exported variable 'Signal'." +// +// A function with the same name is defined later, so we need to ignore TypeScript's +// warning about a redeclared variable. +// +// The class is declared here, but later implemented with ES5-style prototypes. +// This enables better control of the transpiled output size. declare class Signal { /** @internal */ _value: unknown; @@ -239,7 +245,13 @@ declare class Signal { } /** @internal */ -// @ts-ignore internal Signal is viewed as function +// @ts-ignore: "Cannot redeclare exported variable 'Signal'." +// +// A class with the same name has already been declared, so we need to ignore +// TypeScript's warning about a redeclared variable. +// +// The previously declared class is implemented here with ES5-style prototypes. +// This enables better control of the transpiled output size. function Signal(this: Signal, value?: unknown) { this._value = value; this._version = 0; @@ -319,7 +331,7 @@ Signal.prototype.peek = function () { }; Object.defineProperty(Signal.prototype, "value", { - get() { + get(this: Signal) { const node = addDependency(this); if (node !== undefined) { node._version = this._version; @@ -596,7 +608,7 @@ Computed.prototype._notify = function () { }; Object.defineProperty(Computed.prototype, "value", { - get() { + get(this: Computed) { if (this._flags & RUNNING) { throw new Error("Cycle detected"); } From 5fca7b39809e089ec98d30733b8000dc585f673b Mon Sep 17 00:00:00 2001 From: Joachim Viide Date: Fri, 15 Mar 2024 16:00:22 +0000 Subject: [PATCH 2/3] docs: align README.md's section order with the index --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 52a5e4779..26782ea81 100644 --- a/README.md +++ b/README.md @@ -77,23 +77,6 @@ effect(() => { Note that you should only use `signal.peek()` if you really need it. Reading a signal's value via `signal.value` is the preferred way in most scenarios. -### `untracked(fn)` - -In case when you're receiving a callback that can read some signals, but you don't want to subscribe to them, you can use `untracked` to prevent any subscriptions from happening. - -```js -const counter = signal(0); -const effectCount = signal(0); -const fn = () => effectCount.value + 1; - -effect(() => { - console.log(counter.value); - - // Whenever this effect is triggered, run `fn` that gives new value - effectCount.value = untracked(fn); -}); -``` - ### `computed(fn)` Data is often derived from other pieces of existing data. The `computed` function lets you combine the values of multiple signals into a new signal that can be reacted to, or even used by additional computeds. When the signals accessed from within a computed callback change, the computed callback is re-executed and its new return value becomes the computed signal's value. @@ -220,6 +203,23 @@ batch(() => { // Now the callback completed and we'll trigger the effect. ``` +### `untracked(fn)` + +In case when you're receiving a callback that can read some signals, but you don't want to subscribe to them, you can use `untracked` to prevent any subscriptions from happening. + +```js +const counter = signal(0); +const effectCount = signal(0); +const fn = () => effectCount.value + 1; + +effect(() => { + console.log(counter.value); + + // Whenever this effect is triggered, run `fn` that gives new value + effectCount.value = untracked(fn); +}); +``` + ## License `MIT`, see the [LICENSE](./LICENSE) file. From 590a4665e1b9f92d2529a872feb54ffb9cc3a90c Mon Sep 17 00:00:00 2001 From: Joachim Viide Date: Fri, 15 Mar 2024 16:05:45 +0000 Subject: [PATCH 3/3] docs: document effect cleanups --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 26782ea81..715a708a3 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,25 @@ dispose(); surname.value = "Doe 2"; ``` +The effect callback may return a cleanup function. The cleanup function gets run once, either when the effect callback is next called _or_ when the effect gets disposed, whichever happens first. + +```js +import { signal, effect } from "@preact/signals-core"; + +const count = signal(0); + +const dispose = effect(() => { + const c = count.value; + return () => console.log(`cleanup ${c}`); +}); + +// Logs: cleanup 0 +count.value = 1; + +// Logs: cleanup 1 +dispose(); +``` + ### `batch(fn)` The `batch` function allows you to combine multiple signal writes into one single update that is triggered at the end when the callback completes.