diff --git a/.changeset/witty-donuts-explain.md b/.changeset/witty-donuts-explain.md new file mode 100644 index 0000000000..6ee8f66da6 --- /dev/null +++ b/.changeset/witty-donuts-explain.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +chore: clarify when `$effect.pre` runs relative to DOM updates diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index a13fc7bc46..de18add08f 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -205,6 +205,8 @@ In rare cases, you may need to run code _before_ the DOM updates. For this we ca ``` +`$effect.pre` runs before DOM updates that are scheduled after it, not before every DOM mutation in the flush - DOM of parent components may already be updated. When using [await expressions](await-expressions), block updates like `{#if ...}` and `{#each ...}` in the same component also run before `$effect.pre`. + Apart from the timing, `$effect.pre` works exactly like `$effect`. ## `$effect.tracking` diff --git a/documentation/docs/06-runtime/03-lifecycle-hooks.md b/documentation/docs/06-runtime/03-lifecycle-hooks.md index 95e1c260c1..c714dc2e52 100644 --- a/documentation/docs/06-runtime/03-lifecycle-hooks.md +++ b/documentation/docs/06-runtime/03-lifecycle-hooks.md @@ -102,7 +102,7 @@ To implement a chat window that autoscrolls to the bottom when new messages appe In Svelte 4, we do this with `beforeUpdate`, but this is a flawed approach — it fires before _every_ update, whether it's relevant or not. In the example below, we need to introduce checks like `updatingMessages` to make sure we don't mess with the scroll position when someone toggles dark mode. -With runes, we can use `$effect.pre`, which behaves the same as `$effect` but runs before the DOM is updated. As long as we explicitly reference `messages` inside the effect body, it will run whenever `messages` changes, but _not_ when `theme` changes. +With runes, we can use `$effect.pre`, which behaves the same as `$effect` but runs before DOM updates scheduled after it (see [$effect.pre]($effect#$effect.pre) for the exact ordering). As long as we explicitly reference `messages` inside the effect body, it will run whenever `messages` changes, but _not_ when `theme` changes. `beforeUpdate`, and its equally troublesome counterpart `afterUpdate`, are therefore deprecated in Svelte 5. diff --git a/packages/svelte/src/ambient.d.ts b/packages/svelte/src/ambient.d.ts index ed0a004fa1..a9b2cebe1a 100644 --- a/packages/svelte/src/ambient.d.ts +++ b/packages/svelte/src/ambient.d.ts @@ -261,7 +261,7 @@ declare function $effect(fn: () => void | (() => void)): void; declare namespace $effect { /** * Runs code right before a component is mounted to the DOM, and then whenever its dependencies change, i.e. `$state` or `$derived` values. - * The timing of the execution is right before the DOM is updated. + * The timing of the execution is right before the DOM that comes after it is updated; parent DOM may already have been updated by the time it runs. * * Example: * ```ts diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 5fcae1b2e0..96be34ef9e 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -3481,7 +3481,7 @@ declare function $effect(fn: () => void | (() => void)): void; declare namespace $effect { /** * Runs code right before a component is mounted to the DOM, and then whenever its dependencies change, i.e. `$state` or `$derived` values. - * The timing of the execution is right before the DOM is updated. + * The timing of the execution is right before the DOM that comes after it is updated; parent DOM may already have been updated by the time it runs. * * Example: * ```ts