From 52ab33206c8d81f5534dd3a2339e7a65502d1750 Mon Sep 17 00:00:00 2001 From: raythurnvoid <53383860+raythurnvoid@users.noreply.github.com> Date: Thu, 26 Jun 2025 16:39:04 +0100 Subject: [PATCH] Update $effect and testing docs to mention issues with push on state array --- documentation/docs/02-runes/04-$effect.md | 67 +++++++++++++++++++++++ documentation/docs/07-misc/02-testing.md | 8 ++- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index 0e129973d58e..28d6be10a3c7 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -321,4 +321,71 @@ Instead, use `oninput` callbacks or — better still — [function bindings](bin ``` +### untrack + If you absolutely have to update `$state` within an effect and run into an infinite loop because you read and write to the same `$state`, use [untrack](svelte#untrack). + +A common mistake is updating the a `$state` array inside effects (for example `arr.push(item)`). This causes an infinite loop because methods like `push` read the array's `length` property (making the effect depend on it) and also modify it (triggering the effect again): + +```svelte + +``` + +To fix this, wrap the mutation in `untrack`: + +```svelte + +``` + +This applies to all array methods that mutate the array: `push`, `pop`, `shift`, `unshift`, `splice`, etc. The same issue occurs when reassigning a `$state` variable based on its current value, such as `log = [...log, count]`. + +Alternatively, if you don't need the array to be reactive (i.e., changes to it don't need to update the UI), you can use a regular variable instead of `$state`: + +```svelte + +``` \ No newline at end of file diff --git a/documentation/docs/07-misc/02-testing.md b/documentation/docs/07-misc/02-testing.md index db99b7077022..a814d6f6a405 100644 --- a/documentation/docs/07-misc/02-testing.md +++ b/documentation/docs/07-misc/02-testing.md @@ -147,7 +147,13 @@ test('Effect', () => { * @param {() => any} getValue */ export function logger(getValue) { - /** @type {any[]} */ + /** + * must not be a `$state` + * + * @see https://svelte.dev/docs/svelte/$effect#When-not-to-use-$effect-untrack + * + * @type {any[]} + **/ let log = []; $effect(() => {