Svelte 14: $effect.pre & Effect Timing
easy⏱ 5 mincoursesvelte
Two timings, one dependency-tracking engine
$effect.pre and $effect are tracked exactly the same way — read a $state/$derived value inside either one and it becomes a dependency. The ONLY difference is when Svelte calls the callback relative to its own DOM update: $effect.pre runs synchronously right before the DOM patch, plain $effect runs after (asynchronously, batched with other effects).
<script>
let count = $state(0);
$effect.pre(() => {
console.log('about to update DOM, count is', count);
});
$effect(() => {
console.log('DOM already updated, count is', count);
});
</script>
Auto-scroll only if the user was already at the bottom
In the chat below, $effect.pre reads the container's scrollHeight/scrollTop/clientHeight BEFORE the new message is painted, to compute whether the user was scrolled to the bottom. After the DOM updates, a plain $effect uses that stashed flag to snap the scroll position down — but only if they hadn't scrolled up to read history. Getting the order backwards (checking scroll position in a regular $effect) would always measure AFTER the new message already shifted the layout, giving the wrong answer.
Reach for $effect.pre rarely, and on purpose
Most side effects genuinely don't care about pre- vs post-DOM timing, so plain $effect covers the vast majority of real code. Reserve $effect.pre for the narrow case where you must read a DOM measurement that the upcoming update is about to invalidate — scroll position, focus state, or measured element size right before a re-render.