From 8fd7d49c1a55178f09545710d1896a8316b3bb40 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:35:50 -0800 Subject: [PATCH 01/17] docs: address $effect feedback --- .../docs/02-runes/{05-$props.md => 04-$props.md} | 0 .../02-runes/{04-$effect.md => 05-$effect.md} | 16 ++++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) rename documentation/docs/02-runes/{05-$props.md => 04-$props.md} (100%) rename documentation/docs/02-runes/{04-$effect.md => 05-$effect.md} (85%) diff --git a/documentation/docs/02-runes/05-$props.md b/documentation/docs/02-runes/04-$props.md similarity index 100% rename from documentation/docs/02-runes/05-$props.md rename to documentation/docs/02-runes/04-$props.md diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/05-$effect.md similarity index 85% rename from documentation/docs/02-runes/04-$effect.md rename to documentation/docs/02-runes/05-$effect.md index 1ea960de70fc..0b4fae8320c0 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/05-$effect.md @@ -2,15 +2,11 @@ title: $effect --- -Effects are what make your application _do things_. When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed inside [`untrack`](svelte#untrack)), and re-runs the function when that state later changes. +Effects are used for making your application perform _actions_. You might use it to do things like call a third-party library, draw on a `` element, or make a network request. It's important to distinguish these actions from updating state, which should not be done inside an effect. -Most of the effects in a Svelte app are created by Svelte itself — they're the bits that update the text in `

hello {name}!

` when `name` changes, for example. +> [!NOTE] Your application will become a nightmare to deal with almost immediately if you try to update state inside an effect. If you're tempted to use an effect to update state, see [when not to use `$effect`](#When-not-to-use-$effect) to learn about alternative approaches. -But you can also create your own effects with the `$effect` rune, which is useful when you need to synchronize an external system (whether that's a library, or a `` element, or something across a network) with state inside your Svelte app. - -> [!NOTE] Avoid overusing `$effect`! When you do too much work in effects, code often becomes difficult to understand and maintain. See [when not to use `$effect`](#When-not-to-use-$effect) to learn about alternative approaches. - -Your effects run after the component has been mounted to the DOM, and in a [microtask](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide) after state changes ([demo](/playground/untitled#H4sIAAAAAAAAE31S246bMBD9lZF3pSRSAqTVvrCAVPUP2sdSKY4ZwJJjkD0hSVH-vbINuWxXfQH5zMyZc2ZmZLVUaFn6a2R06ZGlHmBrpvnBvb71fWQHVOSwPbf4GS46TajJspRlVhjZU1HqkhQSWPkHIYdXS5xw-Zas3ueI6FRn7qHFS11_xSRZhIxbFtcDtw7SJb1iXaOg5XIFeQGjzyPRaevYNOGZIJ8qogbpe8CWiy_VzEpTXiQUcvPDkSVrSNZz1UlW1N5eLcqmpdXUvaQ4BmqlhZNUCgxuzFHDqUWNAxrYeUM76AzsnOsdiJbrBp_71lKpn3RRbii-4P3f-IMsRxS-wcDV_bL4PmSdBa2wl7pKnbp8DMgVvJm8ZNskKRkEM_OzyOKQFkgqOYBQ3Nq89Ns0nbIl81vMFN-jKoLMTOr-SOBOJS-Z8f5Y6D1wdcR8dFqvEBdetK-PHwj-z-cH8oHPY54wRJ8Ys7iSQ3Bg3VA9azQbmC9k35kKzYa6PoVtfwbbKVnBixBiGn7Pq0rqJoUtHiCZwAM3jdTPWCVtr_glhVrhecIa3vuksJ_b7TqFs4DPyriSjd5IwoNNQaAmNI-ESfR2p8zimzvN1swdCkvJHPH6-_oX8o1SgcIDAAA=)): +You can create an effect with the `$effect` rune ([demo](/playground/untitled#H4sIAAAAAAAAE31S246bMBD9lZF3pSRSAqTVvrCAVPUP2sdSKY4ZwJJjkD0hSVH-vbINuWxXfQH5zMyZc2ZmZLVUaFn6a2R06ZGlHmBrpvnBvb71fWQHVOSwPbf4GS46TajJspRlVhjZU1HqkhQSWPkHIYdXS5xw-Zas3ueI6FRn7qHFS11_xSRZhIxbFtcDtw7SJb1iXaOg5XIFeQGjzyPRaevYNOGZIJ8qogbpe8CWiy_VzEpTXiQUcvPDkSVrSNZz1UlW1N5eLcqmpdXUvaQ4BmqlhZNUCgxuzFHDqUWNAxrYeUM76AzsnOsdiJbrBp_71lKpn3RRbii-4P3f-IMsRxS-wcDV_bL4PmSdBa2wl7pKnbp8DMgVvJm8ZNskKRkEM_OzyOKQFkgqOYBQ3Nq89Ns0nbIl81vMFN-jKoLMTOr-SOBOJS-Z8f5Y6D1wdcR8dFqvEBdetK-PHwj-z-cH8oHPY54wRJ8Ys7iSQ3Bg3VA9azQbmC9k35kKzYa6PoVtfwbbKVnBixBiGn7Pq0rqJoUtHiCZwAM3jdTPWCVtr_glhVrhecIa3vuksJ_b7TqFs4DPyriSjd5IwoNNQaAmNI-ESfR2p8zimzvN1swdCkvJHPH6-_oX8o1SgcIDAAA=)): ```svelte ``` +Note that [when `$effect` runs is different than `$:`]($effect#Understanding-dependencies). + > [!DETAILS] Why we did this > `$:` was a great shorthand and easy to get started with: you could slap a `$:` in front of most code and it would somehow work. This intuitiveness was also its drawback the more complicated your code became, because it wasn't as easy to reason about. Was the intent of the code to create a derivation, or a side effect? With `$derived` and `$effect`, you have a bit more up-front decision making to do (spoiler alert: 90% of the time you want `$derived`), but future-you and other developers on your team will have an easier time. > From 46b2479fe2c1082f3ca301ba0ad8ce2d030c5dea Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Sat, 25 Jan 2025 09:46:32 -0800 Subject: [PATCH 03/17] minor wording tweak --- documentation/docs/07-misc/07-v5-migration-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/07-misc/07-v5-migration-guide.md b/documentation/docs/07-misc/07-v5-migration-guide.md index 8379f38d0df0..350614e79e92 100644 --- a/documentation/docs/07-misc/07-v5-migration-guide.md +++ b/documentation/docs/07-misc/07-v5-migration-guide.md @@ -51,7 +51,7 @@ A `$:` statement could also be used to create side effects. In Svelte 5, this is ``` -Note that [when `$effect` runs is different than `$:`]($effect#Understanding-dependencies). +Note that [when `$effect` runs is different]($effect#Understanding-dependencies) than when `$:` runs. > [!DETAILS] Why we did this > `$:` was a great shorthand and easy to get started with: you could slap a `$:` in front of most code and it would somehow work. This intuitiveness was also its drawback the more complicated your code became, because it wasn't as easy to reason about. Was the intent of the code to create a derivation, or a side effect? With `$derived` and `$effect`, you have a bit more up-front decision making to do (spoiler alert: 90% of the time you want `$derived`), but future-you and other developers on your team will have an easier time. From e6fc4e23cedd982a96c06270392113d66ad694f5 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Sat, 25 Jan 2025 09:52:03 -0800 Subject: [PATCH 04/17] update onMount docs --- packages/svelte/src/index-client.js | 3 +++ packages/svelte/types/index.d.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/svelte/src/index-client.js b/packages/svelte/src/index-client.js index 587d76623331..9ffdf914ec09 100644 --- a/packages/svelte/src/index-client.js +++ b/packages/svelte/src/index-client.js @@ -17,6 +17,9 @@ import { legacy_mode_flag } from './internal/flags/index.js'; * * `onMount` does not run inside [server-side components](https://svelte.dev/docs/svelte/svelte-server#render). * + * `onMount` runs only once. If you need reactivity, you can use [`$effect`](https://svelte.dev/docs/svelte/$effect), + * which also runs when the component is mounted to the DOM. + * * @template T * @param {() => NotFunction | Promise> | (() => any)} fn * @returns {void} diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index d00b2b01ed18..640e0edc5f9c 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -356,6 +356,9 @@ declare module 'svelte' { * * `onMount` does not run inside [server-side components](https://svelte.dev/docs/svelte/svelte-server#render). * + * `onMount` runs only once. If you need reactivity, you can use [`$effect`](https://svelte.dev/docs/svelte/$effect), + * which also runs when the component is mounted to the DOM. + * * */ export function onMount(fn: () => NotFunction | Promise> | (() => any)): void; /** From d68aca8491b53a350a88683c8ce1f7886217fee3 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:07:33 -0800 Subject: [PATCH 05/17] Update documentation/docs/02-runes/05-$effect.md Co-authored-by: Rich Harris --- documentation/docs/02-runes/05-$effect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/02-runes/05-$effect.md b/documentation/docs/02-runes/05-$effect.md index 0b4fae8320c0..754562fd9803 100644 --- a/documentation/docs/02-runes/05-$effect.md +++ b/documentation/docs/02-runes/05-$effect.md @@ -2,7 +2,7 @@ title: $effect --- -Effects are used for making your application perform _actions_. You might use it to do things like call a third-party library, draw on a `` element, or make a network request. It's important to distinguish these actions from updating state, which should not be done inside an effect. +Effects are used for making your application perform _actions_. You might use them to do things like call a third-party library, draw on a `` element, or make a network request. It's important to distinguish these actions from updating state, which should not be done inside an effect. > [!NOTE] Your application will become a nightmare to deal with almost immediately if you try to update state inside an effect. If you're tempted to use an effect to update state, see [when not to use `$effect`](#When-not-to-use-$effect) to learn about alternative approaches. From 31ee22025e2008dddefb60740456d9029d5166e0 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:10:16 -0800 Subject: [PATCH 06/17] restore order --- documentation/docs/02-runes/{05-$effect.md => 04-$effect.md} | 0 documentation/docs/02-runes/{04-$props.md => 05-$props.md} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename documentation/docs/02-runes/{05-$effect.md => 04-$effect.md} (100%) rename documentation/docs/02-runes/{04-$props.md => 05-$props.md} (100%) diff --git a/documentation/docs/02-runes/05-$effect.md b/documentation/docs/02-runes/04-$effect.md similarity index 100% rename from documentation/docs/02-runes/05-$effect.md rename to documentation/docs/02-runes/04-$effect.md diff --git a/documentation/docs/02-runes/04-$props.md b/documentation/docs/02-runes/05-$props.md similarity index 100% rename from documentation/docs/02-runes/04-$props.md rename to documentation/docs/02-runes/05-$props.md From 2f0485914fc88b4a8f565f82788cd04c59c54685 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:28:29 -0800 Subject: [PATCH 07/17] soften a bit --- documentation/docs/02-runes/04-$effect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index 754562fd9803..a5115384df97 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -4,7 +4,7 @@ title: $effect Effects are used for making your application perform _actions_. You might use them to do things like call a third-party library, draw on a `` element, or make a network request. It's important to distinguish these actions from updating state, which should not be done inside an effect. -> [!NOTE] Your application will become a nightmare to deal with almost immediately if you try to update state inside an effect. If you're tempted to use an effect to update state, see [when not to use `$effect`](#When-not-to-use-$effect) to learn about alternative approaches. +> [!NOTE] Updating state inside an effect is considered an anti-pattern and may lead to never-ending cycles of state updates. If you're tempted to use an effect to update state, see [when not to use `$effect`](#When-not-to-use-$effect) to learn about alternative approaches. You can create an effect with the `$effect` rune ([demo](/playground/untitled#H4sIAAAAAAAAE31S246bMBD9lZF3pSRSAqTVvrCAVPUP2sdSKY4ZwJJjkD0hSVH-vbINuWxXfQH5zMyZc2ZmZLVUaFn6a2R06ZGlHmBrpvnBvb71fWQHVOSwPbf4GS46TajJspRlVhjZU1HqkhQSWPkHIYdXS5xw-Zas3ueI6FRn7qHFS11_xSRZhIxbFtcDtw7SJb1iXaOg5XIFeQGjzyPRaevYNOGZIJ8qogbpe8CWiy_VzEpTXiQUcvPDkSVrSNZz1UlW1N5eLcqmpdXUvaQ4BmqlhZNUCgxuzFHDqUWNAxrYeUM76AzsnOsdiJbrBp_71lKpn3RRbii-4P3f-IMsRxS-wcDV_bL4PmSdBa2wl7pKnbp8DMgVvJm8ZNskKRkEM_OzyOKQFkgqOYBQ3Nq89Ns0nbIl81vMFN-jKoLMTOr-SOBOJS-Z8f5Y6D1wdcR8dFqvEBdetK-PHwj-z-cH8oHPY54wRJ8Ys7iSQ3Bg3VA9azQbmC9k35kKzYa6PoVtfwbbKVnBixBiGn7Pq0rqJoUtHiCZwAM3jdTPWCVtr_glhVrhecIa3vuksJ_b7TqFs4DPyriSjd5IwoNNQaAmNI-ESfR2p8zimzvN1swdCkvJHPH6-_oX8o1SgcIDAAA=)): From 8d083e676bc3b1fc17c03000160cb6ea45840170 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:33:10 -0800 Subject: [PATCH 08/17] add back mention of updating template in response to effects --- documentation/docs/02-runes/04-$effect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index a5115384df97..4c5d953677d0 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -28,7 +28,7 @@ You can create an effect with the `$effect` rune ([demo](/playground/untitled#H4 ``` -When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed inside [`untrack`](svelte#untrack)), and re-runs the function when that state later changes. +When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed inside [`untrack`](svelte#untrack)), and re-runs the function when that state later changes. Internally, Svelte uses effects to manage changes to the template — e.g. to update the text in `

hello {name}!

` when `name` changes. > [!NOTE] If you're having difficulty understanding why your `$effect` is rerunning or is not running see [understanding dependencies](#Understanding-dependencies). Effects are triggered differently than the `$:` blocks you may be used to if coming from Svelte 4. From 338dea6ac5ac8532baea8fed1dadfce4ca62895d Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:36:03 -0800 Subject: [PATCH 09/17] define parent effect --- documentation/docs/02-runes/04-$effect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index 4c5d953677d0..6cbdf5904ab6 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -34,7 +34,7 @@ When Svelte runs an effect function, it tracks which pieces of state (and derive Your effects run after the component has been mounted to the DOM, and in a [microtask](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide) after state changes. Re-runs are batched (i.e. changing `color` and `size` in the same moment won't cause two separate runs), and happen after any DOM updates have been applied. -You can place `$effect` anywhere, not just at the top level of a component, as long as it is called during component initialization (or while a parent effect is active). It is then tied to the lifecycle of the component (or parent effect) and will therefore destroy itself when the component unmounts (or the parent effect is destroyed). +Effects must be executed within a parent effect, which can be the `$effect.root`, another `$effect`, or `$effect.pre`. You can place an `$effect` anywhere, not just at the top level of a component, as long as it is called during component initialization (or while a parent effect is active). It is then tied to the lifecycle of the component (or parent effect) and will therefore destroy itself when the component unmounts (or the parent effect is destroyed). You can return a function from `$effect`, which will run immediately before the effect re-runs, and before it is destroyed ([demo](/playground/untitled#H4sIAAAAAAAAE42RQY-bMBCF_8rI2kPopiXpMQtIPfbeW6m0xjyKtWaM7CFphPjvFVB2k2oPe7LmzXzyezOjaqxDVKefo5JrD3VaBLVXrLu5-tb3X-IZTmat0hHv6cazgCWqk8qiCbaXouRSHISMH1gop4coWrA7JE9bp7PO2QjjuY5vA8fDYZ3hUh7QNDCy2yWUFzTOUilpSj9aG-linaMKFGACtKCmSwvGGYGeLQvCWbtnMq3m34grajxHoa1JOUXI93_V_Sfz7Oz7Mafj0ypN-zvHm8dSAmQITP_xaUq2IU1GO1dp80I2Uh_82dao92Rl9R8GvgF0QrbrUFstcFeq0PgAkha0LoICPoeB4w1SJUvsZcj4rvcMlvmvGlGCv6J-DeSgw2vabQnJlm55p7nM0rcTctYei3HZxZSl7XHVqkHEM3k2zpqXfFyj393zU05fpyI6f0HI0hUoPoamC9roKDeo2ivBH1EnCQOmX9NfYw2GHrgCAAA=)). From e6bbc49790e4172a53c698f89e642b171169b937 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:39:18 -0800 Subject: [PATCH 10/17] state that they don't run on the server --- documentation/docs/02-runes/04-$effect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index 6cbdf5904ab6..63711432878b 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -2,7 +2,7 @@ title: $effect --- -Effects are used for making your application perform _actions_. You might use them to do things like call a third-party library, draw on a `` element, or make a network request. It's important to distinguish these actions from updating state, which should not be done inside an effect. +Effects are used for making your application perform _actions_ in the browser. Effects do not run on the server. You might use them to do things like call a third-party library, draw on a `` element, or make a network request. It's important to distinguish these actions from updating state, which should not be done inside an effect. > [!NOTE] Updating state inside an effect is considered an anti-pattern and may lead to never-ending cycles of state updates. If you're tempted to use an effect to update state, see [when not to use `$effect`](#When-not-to-use-$effect) to learn about alternative approaches. From 61a93c827f2d48e7a172e15a6ea436d0f21487fd Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Thu, 30 Jan 2025 12:59:10 -0800 Subject: [PATCH 11/17] Update documentation/docs/02-runes/04-$effect.md Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> --- documentation/docs/02-runes/04-$effect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index 63711432878b..acddbef1d579 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -34,7 +34,7 @@ When Svelte runs an effect function, it tracks which pieces of state (and derive Your effects run after the component has been mounted to the DOM, and in a [microtask](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide) after state changes. Re-runs are batched (i.e. changing `color` and `size` in the same moment won't cause two separate runs), and happen after any DOM updates have been applied. -Effects must be executed within a parent effect, which can be the `$effect.root`, another `$effect`, or `$effect.pre`. You can place an `$effect` anywhere, not just at the top level of a component, as long as it is called during component initialization (or while a parent effect is active). It is then tied to the lifecycle of the component (or parent effect) and will therefore destroy itself when the component unmounts (or the parent effect is destroyed). +You can place `$effect` anywhere, not just at the top level of a component, as long as it is called during component initialization. It is then tied to the lifecycle of the component and will therefore destroy itself when the component unmounts. You can also place it within parent effects (i.e. within `$effect.root`, another `$effect`, or `$effect.pre`), which means it is tied to the lifecycle of its parent effect, and will destroy itself when the parent is destroyed. You can return a function from `$effect`, which will run immediately before the effect re-runs, and before it is destroyed ([demo](/playground/untitled#H4sIAAAAAAAAE42RQY-bMBCF_8rI2kPopiXpMQtIPfbeW6m0xjyKtWaM7CFphPjvFVB2k2oPe7LmzXzyezOjaqxDVKefo5JrD3VaBLVXrLu5-tb3X-IZTmat0hHv6cazgCWqk8qiCbaXouRSHISMH1gop4coWrA7JE9bp7PO2QjjuY5vA8fDYZ3hUh7QNDCy2yWUFzTOUilpSj9aG-linaMKFGACtKCmSwvGGYGeLQvCWbtnMq3m34grajxHoa1JOUXI93_V_Sfz7Oz7Mafj0ypN-zvHm8dSAmQITP_xaUq2IU1GO1dp80I2Uh_82dao92Rl9R8GvgF0QrbrUFstcFeq0PgAkha0LoICPoeB4w1SJUvsZcj4rvcMlvmvGlGCv6J-DeSgw2vabQnJlm55p7nM0rcTctYei3HZxZSl7XHVqkHEM3k2zpqXfFyj393zU05fpyI6f0HI0hUoPoamC9roKDeo2ivBH1EnCQOmX9NfYw2GHrgCAAA=)). From b27ca05c5c8cb38a8f10e72e88a057a17a6b4685 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Fri, 31 Jan 2025 08:07:29 -0800 Subject: [PATCH 12/17] format --- packages/svelte/src/index-client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/index-client.js b/packages/svelte/src/index-client.js index 9ffdf914ec09..ce254f7bdccb 100644 --- a/packages/svelte/src/index-client.js +++ b/packages/svelte/src/index-client.js @@ -19,7 +19,7 @@ import { legacy_mode_flag } from './internal/flags/index.js'; * * `onMount` runs only once. If you need reactivity, you can use [`$effect`](https://svelte.dev/docs/svelte/$effect), * which also runs when the component is mounted to the DOM. - * + * * @template T * @param {() => NotFunction | Promise> | (() => any)} fn * @returns {void} From fbd1e51e91949817825a3a753f977a322eecccfd Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 5 Mar 2025 21:24:10 -0500 Subject: [PATCH 13/17] Apply suggestions from code review Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> --- documentation/docs/02-runes/04-$effect.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index acddbef1d579..32424fe0f276 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -2,9 +2,9 @@ title: $effect --- -Effects are used for making your application perform _actions_ in the browser. Effects do not run on the server. You might use them to do things like call a third-party library, draw on a `` element, or make a network request. It's important to distinguish these actions from updating state, which should not be done inside an effect. +Effects are functions that run when state updates, and can be used for things like calling third-party libraries, drawing on `` elements, or making network requests. They only run in the browser, not during server-side rendering. -> [!NOTE] Updating state inside an effect is considered an anti-pattern and may lead to never-ending cycles of state updates. If you're tempted to use an effect to update state, see [when not to use `$effect`](#When-not-to-use-$effect) to learn about alternative approaches. +Generally speaking, you should _not_ update state inside effects, as it will make code more convoluted and will often lead to never-ending update cycles. If you find yourself doing so, see [when not to use `$effect`](#When-not-to-use-$effect) to learn about alternative approaches. You can create an effect with the `$effect` rune ([demo](/playground/untitled#H4sIAAAAAAAAE31S246bMBD9lZF3pSRSAqTVvrCAVPUP2sdSKY4ZwJJjkD0hSVH-vbINuWxXfQH5zMyZc2ZmZLVUaFn6a2R06ZGlHmBrpvnBvb71fWQHVOSwPbf4GS46TajJspRlVhjZU1HqkhQSWPkHIYdXS5xw-Zas3ueI6FRn7qHFS11_xSRZhIxbFtcDtw7SJb1iXaOg5XIFeQGjzyPRaevYNOGZIJ8qogbpe8CWiy_VzEpTXiQUcvPDkSVrSNZz1UlW1N5eLcqmpdXUvaQ4BmqlhZNUCgxuzFHDqUWNAxrYeUM76AzsnOsdiJbrBp_71lKpn3RRbii-4P3f-IMsRxS-wcDV_bL4PmSdBa2wl7pKnbp8DMgVvJm8ZNskKRkEM_OzyOKQFkgqOYBQ3Nq89Ns0nbIl81vMFN-jKoLMTOr-SOBOJS-Z8f5Y6D1wdcR8dFqvEBdetK-PHwj-z-cH8oHPY54wRJ8Ys7iSQ3Bg3VA9azQbmC9k35kKzYa6PoVtfwbbKVnBixBiGn7Pq0rqJoUtHiCZwAM3jdTPWCVtr_glhVrhecIa3vuksJ_b7TqFs4DPyriSjd5IwoNNQaAmNI-ESfR2p8zimzvN1swdCkvJHPH6-_oX8o1SgcIDAAA=)): @@ -28,7 +28,7 @@ You can create an effect with the `$effect` rune ([demo](/playground/untitled#H4 ``` -When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed inside [`untrack`](svelte#untrack)), and re-runs the function when that state later changes. Internally, Svelte uses effects to manage changes to the template — e.g. to update the text in `

hello {name}!

` when `name` changes. +When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed inside [`untrack`](svelte#untrack)), and re-runs the function when that state later changes. > [!NOTE] If you're having difficulty understanding why your `$effect` is rerunning or is not running see [understanding dependencies](#Understanding-dependencies). Effects are triggered differently than the `$:` blocks you may be used to if coming from Svelte 4. From 67a6d9bcd19918bcc3eafae098e63e3458a954e4 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 5 Mar 2025 21:31:11 -0500 Subject: [PATCH 14/17] update onMount docs --- packages/svelte/src/index-client.js | 14 ++++++-------- packages/svelte/types/index.d.ts | 14 ++++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/svelte/src/index-client.js b/packages/svelte/src/index-client.js index ce254f7bdccb..b002075470a1 100644 --- a/packages/svelte/src/index-client.js +++ b/packages/svelte/src/index-client.js @@ -9,16 +9,14 @@ import { lifecycle_outside_component } from './internal/shared/errors.js'; import { legacy_mode_flag } from './internal/flags/index.js'; /** - * The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM. - * It must be called during the component's initialisation (but doesn't need to live *inside* the component; - * it can be called from an external module). + * `onMount`, like [`$effect`](https://svelte.dev/docs/svelte/$effect), schedules a function to run as soon as the component has been mounted to the DOM. + * Unlike `$effect`, the provided function only runs once. * - * If a function is returned _synchronously_ from `onMount`, it will be called when the component is unmounted. + * It must be called during the component's initialisation (but doesn't need to live _inside_ the component; + * it can be called from an external module). If a function is returned _synchronously_ from `onMount`, + * it will be called when the component is unmounted. * - * `onMount` does not run inside [server-side components](https://svelte.dev/docs/svelte/svelte-server#render). - * - * `onMount` runs only once. If you need reactivity, you can use [`$effect`](https://svelte.dev/docs/svelte/$effect), - * which also runs when the component is mounted to the DOM. + * `onMount` functions do not run during [server-side rendering](https://svelte.dev/docs/svelte/svelte-server#render). * * @template T * @param {() => NotFunction | Promise> | (() => any)} fn diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 640e0edc5f9c..ecb8ff3d1d73 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -348,16 +348,14 @@ declare module 'svelte' { props: Props; }); /** - * The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM. - * It must be called during the component's initialisation (but doesn't need to live *inside* the component; - * it can be called from an external module). + * `onMount`, like [`$effect`](https://svelte.dev/docs/svelte/$effect), schedules a function to run as soon as the component has been mounted to the DOM. + * Unlike `$effect`, the provided function only runs once. * - * If a function is returned _synchronously_ from `onMount`, it will be called when the component is unmounted. + * It must be called during the component's initialisation (but doesn't need to live _inside_ the component; + * it can be called from an external module). If a function is returned _synchronously_ from `onMount`, + * it will be called when the component is unmounted. * - * `onMount` does not run inside [server-side components](https://svelte.dev/docs/svelte/svelte-server#render). - * - * `onMount` runs only once. If you need reactivity, you can use [`$effect`](https://svelte.dev/docs/svelte/$effect), - * which also runs when the component is mounted to the DOM. + * `onMount` functions do not run during [server-side rendering](https://svelte.dev/docs/svelte/svelte-server#render). * * */ export function onMount(fn: () => NotFunction | Promise> | (() => any)): void; From 698b4c0f8a856a75b4defa8e403e40489a476faa Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 5 Mar 2025 21:42:26 -0500 Subject: [PATCH 15/17] add 'Understanding lifecycle' section --- documentation/docs/02-runes/04-$effect.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index 32424fe0f276..2b5952255abc 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -32,11 +32,15 @@ When Svelte runs an effect function, it tracks which pieces of state (and derive > [!NOTE] If you're having difficulty understanding why your `$effect` is rerunning or is not running see [understanding dependencies](#Understanding-dependencies). Effects are triggered differently than the `$:` blocks you may be used to if coming from Svelte 4. +### Understanding lifecycle + Your effects run after the component has been mounted to the DOM, and in a [microtask](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide) after state changes. Re-runs are batched (i.e. changing `color` and `size` in the same moment won't cause two separate runs), and happen after any DOM updates have been applied. -You can place `$effect` anywhere, not just at the top level of a component, as long as it is called during component initialization. It is then tied to the lifecycle of the component and will therefore destroy itself when the component unmounts. You can also place it within parent effects (i.e. within `$effect.root`, another `$effect`, or `$effect.pre`), which means it is tied to the lifecycle of its parent effect, and will destroy itself when the parent is destroyed. +You can use `$effect` anywhere, not just at the top level of a component, as long as it is called while a parent effect is running. + +> Svelte uses effects internally to represent logic and expressions in your template — this is how `

hello {name}!

` updates when `name` changes. -You can return a function from `$effect`, which will run immediately before the effect re-runs, and before it is destroyed ([demo](/playground/untitled#H4sIAAAAAAAAE42RQY-bMBCF_8rI2kPopiXpMQtIPfbeW6m0xjyKtWaM7CFphPjvFVB2k2oPe7LmzXzyezOjaqxDVKefo5JrD3VaBLVXrLu5-tb3X-IZTmat0hHv6cazgCWqk8qiCbaXouRSHISMH1gop4coWrA7JE9bp7PO2QjjuY5vA8fDYZ3hUh7QNDCy2yWUFzTOUilpSj9aG-linaMKFGACtKCmSwvGGYGeLQvCWbtnMq3m34grajxHoa1JOUXI93_V_Sfz7Oz7Mafj0ypN-zvHm8dSAmQITP_xaUq2IU1GO1dp80I2Uh_82dao92Rl9R8GvgF0QrbrUFstcFeq0PgAkha0LoICPoeB4w1SJUvsZcj4rvcMlvmvGlGCv6J-DeSgw2vabQnJlm55p7nM0rcTctYei3HZxZSl7XHVqkHEM3k2zpqXfFyj393zU05fpyI6f0HI0hUoPoamC9roKDeo2ivBH1EnCQOmX9NfYw2GHrgCAAA=)). +An effect can return a _teardown function_ which will run immediately before the effect re-runs ([demo](/playground/untitled#H4sIAAAAAAAAE42RQY-bMBCF_8rI2kPopiXpMQtIPfbeW6m0xjyKtWaM7CFphPjvFVB2k2oPe7LmzXzyezOjaqxDVKefo5JrD3VaBLVXrLu5-tb3X-IZTmat0hHv6cazgCWqk8qiCbaXouRSHISMH1gop4coWrA7JE9bp7PO2QjjuY5vA8fDYZ3hUh7QNDCy2yWUFzTOUilpSj9aG-linaMKFGACtKCmSwvGGYGeLQvCWbtnMq3m34grajxHoa1JOUXI93_V_Sfz7Oz7Mafj0ypN-zvHm8dSAmQITP_xaUq2IU1GO1dp80I2Uh_82dao92Rl9R8GvgF0QrbrUFstcFeq0PgAkha0LoICPoeB4w1SJUvsZcj4rvcMlvmvGlGCv6J-DeSgw2vabQnJlm55p7nM0rcTctYei3HZxZSl7XHVqkHEM3k2zpqXfFyj393zU05fpyI6f0HI0hUoPoamC9roKDeo2ivBH1EnCQOmX9NfYw2GHrgCAAA=)). ```svelte