{"id":3067,"date":"2024-07-19T13:40:23","date_gmt":"2024-07-19T18:40:23","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=3067"},"modified":"2024-08-11T17:15:59","modified_gmt":"2024-08-11T22:15:59","slug":"introducing-svelte-5","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/introducing-svelte-5\/","title":{"rendered":"Introducing Svelte 5"},"content":{"rendered":"\n<p><a href=\"https:\/\/svelte.dev\/\">Svelte<\/a> has always been a delightful, simple, and fun framework to use. It&#8217;s a framework that&#8217;s always prioritized developer experience (DX), while producing a light and fast result with minimal JavaScript. It achieves this nice DX by giving users dirt simple idioms and a required compiler that makes everything work. Unfortunately, it used to be fairly easy to break Svelte&#8217;s reactivity. It doesn&#8217;t matter how fast a website is if it&#8217;s broken.<\/p>\n\n\n\n<p>These reliability problems with reactivity are gone in Svelte 5.<\/p>\n\n\n\n<p>In this post, we&#8217;ll get into the exciting Svelte 5 release (in Beta at the time of this writing). Svelte is the latest framework to add <strong>signals<\/strong> to power their reactivity. Svelte is now every bit as capable of handling robust web applications, with complex state, as alternatives like React and Solid. Best of all, it achieved this with only minimal hits to DX. It&#8217;s every bit as fun and easy to use as it was, but it&#8217;s now truly reliable, while still producing faster and lighter sites.<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/introducing-svelte-5\/\">Introducing Svelte 5<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/snippets-in-svelte-5\/\">Snippets in Svelte 5<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/fine-grained-reactivity-in-svelte-5\/\">Fine-Grained Reactivity in Svelte 5<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n\n\n\n<p>Let&#8217;s jump in!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-plan\">The Plan<\/h2>\n\n\n\n<p>Let&#8217;s go through various pieces of Svelte, look at the &#8220;old&#8221; way, and then see how Svelte 5 changes things for the better. We&#8217;ll cover: <\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"#state\">State<\/a><\/li>\n\n\n\n<li><a href=\"#props\" data-type=\"internal\" data-id=\"#props\">Props<\/a><\/li>\n\n\n\n<li><a href=\"#effects\">Effects<\/a><\/li>\n<\/ol>\n\n\n\n<p>If you find this helpful, let me know, as I&#8217;d love to cover snippets and Svelte&#8217;s exciting new fine-grained reactivity.<\/p>\n\n\n\n<p class=\"learn-more\">As of this writing, Svelte 5 is late in the Beta phase. The API should be stable, although it&#8217;s certainly possible some new things might get added.<\/p>\n\n\n\n<p>The docs are also still in beta, so <a href=\"https:\/\/svelte-5-preview.vercel.app\/docs\/introduction\">here&#8217;s a preview URL for them<\/a>. Svelte 5 <em>might<\/em> be released when you read this, at which point these docs will be on the main Svelte page. If you&#8217;d like to see the code samples below in action, you can find them in&nbsp;<a href=\"https:\/\/github.com\/arackaf\/svelte-5-intro-blog\">this repo<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"state\">State<\/h2>\n\n\n\n<p>Effectively managing state is probably the most crucial task for any web framework, so let&#8217;s start there.<\/p>\n\n\n\n<p>State used to be declared with regular, plain old variable declarations, using&nbsp;<code>let<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> value = <span class=\"hljs-number\">0<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Derived state was declared with a quirky, but technically valid JavaScript syntax of&nbsp;<code>$:<\/code>. For example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> value = <span class=\"hljs-number\">0<\/span>;\n$: doubleValue = value * <span class=\"hljs-number\">2<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Svelte&#8217;s compiler would (in theory) track changes to&nbsp;<code>value<\/code>, and update&nbsp;<code>doubleValue<\/code>&nbsp;accordingly. I say <em>in theory<\/em> since, depending on how creatively you used&nbsp;<code>value<\/code>, some of the re-assignments might not make it to all of the derived state that used it.<\/p>\n\n\n\n<p>You could also put entire code blocks after&nbsp;<code>$:<\/code>&nbsp;and run arbitrary code. Svelte would look at what you were referencing inside the code block, and re-run it when those things changed.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">$: {\n  <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">\"Value is \"<\/span>, value);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\" id=\"stores\">Stores<\/h3>\n\n\n\n<p>Those variable declarations, and the special&nbsp;<code>$:<\/code>&nbsp;syntax was limited to Svelte components. If you wanted to build some portable state you could define anywhere, and pass around, you&#8217;d use a&nbsp;<a href=\"https:\/\/svelte.dev\/docs\/svelte-store\">store<\/a>.<\/p>\n\n\n\n<p>We won&#8217;t go through the whole API, but here&#8217;s a minimal example of a store in action. We&#8217;ll define a piece of state that holds a number, and, based on what that number is at anytime, spit out a label indicating whether the number is even or odd. It&#8217;s silly, but it should show us how stores work.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> { derived, writable } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"svelte\/store\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">createNumberInfo<\/span>(<span class=\"hljs-params\">initialValue: number = <span class=\"hljs-number\">0<\/span><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> value = writable(initialValue);\n\n  <span class=\"hljs-keyword\">const<\/span> derivedInfo = derived(value, value =&gt; {\n    <span class=\"hljs-keyword\">return<\/span> {\n      value,\n      <span class=\"hljs-attr\">label<\/span>: value % <span class=\"hljs-number\">2<\/span> ? <span class=\"hljs-string\">\"Odd number\"<\/span> : <span class=\"hljs-string\">\"Even number\"<\/span>,\n    };\n  });\n\n  <span class=\"hljs-keyword\">return<\/span> {\n    update(newValue: number) {\n      value.set(newValue);\n    },\n    <span class=\"hljs-attr\">numberInfo<\/span>: derivedInfo,\n  };\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Writable stores exist to write values to. <em>Derived<\/em> stores take one or more <em>other<\/em> stores, read their current values, and project a new payload. If you want to provide a mechanism to set a new value, close over what you need to. To consume a store&#8217;s value, prefix it with a&nbsp;<code>$<\/code>&nbsp;in a Svelte component. It&#8217;s not shown here, but there&#8217;s also a&nbsp;<code>subscribe<\/code>&nbsp;method on stores, and a&nbsp;<code>get<\/code>&nbsp;import. If the store returns an object with properties, you can either &#8220;dot through&#8221; to them, or you can use a reactive assignment (<code>$:<\/code>) to get those nested values. The example below shows both, and this distinction will come up later when we talk about interoperability between Svelte 4 and 5.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"javascript\">\n  <span class=\"hljs-keyword\">import<\/span> { createNumberInfo } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/numberInfoStore'<\/span>;\n\n  <span class=\"hljs-keyword\">let<\/span> store = createNumberInfo(<span class=\"hljs-number\">0<\/span>);\n\n  $: ({ numberInfo, update } = store);\n  $: ({ label, value } = $numberInfo);\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"flex flex-col gap-2 p-5\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>{$numberInfo.value}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>{$numberInfo.label}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">hr<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>{value}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>{label}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onclick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> update($numberInfo.value + 1)}&gt;\n    Increment count\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This was the <em>old<\/em> Svelte.<\/p>\n\n\n\n<p>This is a post on the <em>new<\/em> Svelte, so let&#8217;s turn our attention there.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"state-in-svelte-5\">State in Svelte 5<\/h2>\n\n\n\n<p>Things are substantially simpler in Svelte 5. Pretty much everything is managed by something new called &#8220;runes.&#8221; Let&#8217;s see what that means.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"runes\">Runes<\/h3>\n\n\n\n<p>Svelte 5 joins the increasing number of JavaScript frameworks that use the concept of <em>signals<\/em>. There is a new feature called <em>runes<\/em> and under the covers they use signals. These accomplish a wide range of features from state to props and even side effects. <a href=\"https:\/\/svelte.dev\/blog\/runes\">Here&#8217;s a good introduction to runes<\/a>.<\/p>\n\n\n\n<p>To create a piece of state, we use the&nbsp;<code>$state<\/code>&nbsp;rune. You don&#8217;t import it, you just use it \u2014 it&#8217;s part of the Svelte language.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> count = $state(<span class=\"hljs-number\">0<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>For values with non-inferable types, you can provide a generic<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> currentUser = $state&lt;User | <span class=\"hljs-literal\">null<\/span>&gt;(<span class=\"hljs-literal\">null<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>What if you want to create some derived state? Before we did:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">$: countTimes2 = count * <span class=\"hljs-number\">2<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In Svelte 5 we use the&nbsp;<code>$derived<\/code>&nbsp;rune.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> countTimes2 = $derived(count * <span class=\"hljs-number\">2<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Note that we pass in a raw&nbsp;<em>expression<\/em>. Svelte will run it, see what it depends on, and re-run it as needed. There&#8217;s also a&nbsp;<code>$derived.by<\/code>&nbsp;rune if you want to pass an actual function.<\/p>\n\n\n\n<p>If you want to use these state values in a Svelte template, you just&nbsp;<em>use them<\/em>. No need for special&nbsp;<code>$<\/code>&nbsp;syntax to prefix the runes like we did with stores. You reference the values in your templates, and they update as needed.<\/p>\n\n\n\n<p>If you want to&nbsp;<em>update<\/em>&nbsp;a state value, you assign to it:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">count = count + <span class=\"hljs-number\">1<\/span>;\n<span class=\"hljs-comment\">\/\/ or count++;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\" id=\"what-about-stores\">What about stores?<\/h3>\n\n\n\n<p>We saw before that defining portable state outside of components was accomplished via stores. Stores are not deprecated in Svelte 5, but there&#8217;s a good chance they&#8217;re on their way out of the framework. You no longer need them, and they&#8217;re replaced with what we&#8217;ve&nbsp;<em>already seen<\/em>. That&#8217;s right, the&nbsp;<code>$state<\/code>&nbsp;and&nbsp;<code>$derived<\/code>&nbsp;runes we saw before can be defined outside of components in top-level TypeScript (or JavaScript) files. Just be sure to name your file with a&nbsp;<code>.svelte.ts<\/code>&nbsp;extension, so the Svelte compiler knows to enable runes in these files. Let&#8217;s take a look!<\/p>\n\n\n\n<p>Let&#8217;s re-implement our number \/ label code from before, in Svelte 5. This is what it looked like with stores:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> { derived, writable } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"svelte\/store\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">createNumberInfo<\/span>(<span class=\"hljs-params\">initialValue: number = <span class=\"hljs-number\">0<\/span><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> value = writable(initialValue);\n\n  <span class=\"hljs-keyword\">const<\/span> derivedInfo = derived(value, value =&gt; {\n    <span class=\"hljs-keyword\">return<\/span> {\n      value,\n      <span class=\"hljs-attr\">label<\/span>: value % <span class=\"hljs-number\">2<\/span> ? <span class=\"hljs-string\">\"Odd number\"<\/span> : <span class=\"hljs-string\">\"Even number\"<\/span>,\n    };\n  });\n\n  <span class=\"hljs-keyword\">return<\/span> {\n    update(newValue: number) {\n      value.set(newValue);\n    },\n    <span class=\"hljs-attr\">numberInfo<\/span>: derivedInfo,\n  };\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here it is with runes:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">createNumberInfo<\/span>(<span class=\"hljs-params\">initialValue: number = <span class=\"hljs-number\">0<\/span><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">let<\/span> value = $state(initialValue);\n  <span class=\"hljs-keyword\">let<\/span> label = $derived(value % <span class=\"hljs-number\">2<\/span> ? <span class=\"hljs-string\">\"Odd number\"<\/span> : <span class=\"hljs-string\">\"Even number\"<\/span>);\n\n  <span class=\"hljs-keyword\">return<\/span> {\n    update(newValue: number) {\n      value = newValue;\n    },\n    <span class=\"hljs-keyword\">get<\/span> value() {\n      <span class=\"hljs-keyword\">return<\/span> value;\n    },\n    <span class=\"hljs-keyword\">get<\/span> label() {\n      <span class=\"hljs-keyword\">return<\/span> label;\n    },\n  };\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>It&#8217;s 3 lines shorter, but more importantly,&nbsp;<em>much<\/em>&nbsp;simpler. We declared our state. We computed our derived state. And we send them both back, along with a method that updates our state.<\/p>\n\n\n\n<p>You may be wondering why we did this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">  <span class=\"hljs-keyword\">get<\/span> value() {\n    <span class=\"hljs-keyword\">return<\/span> value;\n  },\n  <span class=\"hljs-keyword\">get<\/span> label() {\n    <span class=\"hljs-keyword\">return<\/span> label;\n  }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>rather than just referencing those properties. The reason is that&nbsp;<em>reading<\/em>&nbsp;that state, at any given point in time, evaluates the state rune, and, if we&#8217;re reading it in a reactive context (like a Svelte component binding, or inside of a <code>$derived<\/code> expression), then a subscription is set up to update any time that piece of state is updated. If we had done it like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ this won't work<\/span>\n<span class=\"hljs-keyword\">return<\/span> {\n  update(newValue: number) {\n    value = newValue;\n  },\n  value,\n  label,\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That wouldn&#8217;t have worked because those <code>value<\/code> and <code>label<\/code> pieces of state would be <em>read and evaluated right there<\/em> in the return value, with those raw values getting injected into that object. They would not be reactive, and they would never update.<\/p>\n\n\n\n<p>That&#8217;s about it! Svelte 5 ships a few universal state primitives which can be used outside of components and easily constructed into larger reactive structures. What&#8217;s especially exciting is that Svelte&#8217;s component bindings are also updated, and now support fine-grained reactivity that didn\u2019t used to exist.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"props\">Props<\/h2>\n\n\n\n<p>Defining state inside of a component isn&#8217;t too useful if you can&#8217;t pass it on to other components as props. Props are also reworked in Svelte 5 in a way that makes them simpler, and also, as we&#8217;ll see, includes a nice trick to make TypeScript integration more powerful.<\/p>\n\n\n\n<p>Svelte 4 props were another example of hijacking existing JavaScript syntax to do something unrelated. To declare a prop on a component, you&#8217;d use the <code>export<\/code> keyword. It was weird, but it worked.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">\/\/ ChildComponent.svelte\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"javascript\">\n  <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> name: string;\n  <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> age: number;\n  <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> currentValue: string;\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"flex flex-col gap-2\"<\/span>&gt;<\/span>\n  {name} {age}\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">bind:value<\/span>=<span class=\"hljs-string\">{currentValue}<\/span> \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This component created three props. It also bound the&nbsp;<code>currentValue<\/code>&nbsp;prop into the <code>&lt;input&gt;<\/code>, so it would change as the user typed. Then to render this component, we&#8217;d do something like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"javascript\">\n  <span class=\"hljs-keyword\">import<\/span> ChildComponent <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/ChildComponent.svelte\"<\/span>;\n\n  <span class=\"hljs-keyword\">let<\/span> currentValue = <span class=\"hljs-string\">\"\"<\/span>;\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\nCurrent value in parent: {currentValue}\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ChildComponent<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"Bob\"<\/span> <span class=\"hljs-attr\">age<\/span>=<span class=\"hljs-string\">{20}<\/span> <span class=\"hljs-attr\">bind:currentValue<\/span> \/&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This is Svelte 4, so&nbsp;<code>let currentValue = ''<\/code>&nbsp;is a piece of state that can change. We pass props for name and age, but we also have&nbsp;<code>bind:currentValue<\/code>&nbsp;which is a shorthand for&nbsp;<code>bind:currentValue={currentValue}<\/code>. This creates a&nbsp;<em>two-way binding<\/em>. As the child changes the value of this prop, it propagates the change upward, to the parent. This is a very cool feature of Svelte, but it&#8217;s also easy to misuse, so exercise caution.<\/p>\n\n\n\n<p>If we type in the ChildComponent&#8217;s <code>&lt;input&gt;<\/code>, we&#8217;ll see <code>currentValue<\/code> update in the parent component.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"svelte-5-version\">Svelte 5 version<\/h3>\n\n\n\n<p>Let&#8217;s see what these props look like in Svelte 5.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"javascript\">\n  type Props = {\n    <span class=\"hljs-attr\">name<\/span>: string;\n    age: number;\n    currentValue: string;\n  };\n\n  <span class=\"hljs-keyword\">let<\/span> { age, name, currentValue = $bindable() }: Props = $props();\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"flex flex-col gap-2\"<\/span>&gt;<\/span>\n  {name} {age}\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">bind:value<\/span>=<span class=\"hljs-string\">{currentValue}<\/span> \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The props are defined via the&nbsp;<code>$props<\/code>&nbsp;rune, from which we destructure the individual values.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">let<\/span> { age, name, currentValue = $bindable() }: Props = $props();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We can apply typings directly to the destructuring expression. In order to indicate that a prop&nbsp;<em>can be<\/em>&nbsp;(but doesn&#8217;t have to be) bound to the parent, like we saw above, we use the&nbsp;<code>$bindable<\/code>&nbsp;rune, like this<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"> = $bindable()<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If you want to provide a default value, assign it to the destructured value. To assign a default value to a bindable prop, pass that value to the&nbsp;<code>$bindable<\/code>&nbsp;rune.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">let<\/span> { age = <span class=\"hljs-number\">10<\/span>, name = <span class=\"hljs-string\">\"foo\"<\/span>, currentValue = $bindable(<span class=\"hljs-string\">\"bar\"<\/span>) }: Props = $props();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\" id=\"but-wait-theres-more\">But wait, there&#8217;s more!<\/h3>\n\n\n\n<p>One of the most exciting changes to Svelte&#8217;s prop handling is the improved TypeScript integration. We saw that you can assign types, above. But what if we want to do something like this (in React)<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">type<\/span> Props&lt;T&gt; = {\n  items: T&#91;];\n  onSelect: <span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">item<\/span>: <span class=\"hljs-params\">T<\/span><\/span>) =&gt;<\/span> <span class=\"hljs-built_in\">void<\/span>;\n};\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> AutoComplete = &lt;T,&gt;<span class=\"hljs-function\">(<span class=\"hljs-params\"><span class=\"hljs-params\">props<\/span>: <span class=\"hljs-params\">Props<\/span>&lt;<span class=\"hljs-params\">T<\/span>&gt;<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">null<\/span>;\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We want a React component that receives an array of items, as well as a callback that takes a single item (of the same type). This works in React. How would we do it in Svelte?<\/p>\n\n\n\n<p>At first, it looks easy.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"javascript\">\n  type Props&lt;T&gt; = {\n    <span class=\"hljs-attr\">items<\/span>: T&#91;];\n    onSelect: <span class=\"hljs-function\">(<span class=\"hljs-params\">item: T<\/span>) =&gt;<\/span> <span class=\"hljs-keyword\">void<\/span>;\n  };\n\n  <span class=\"hljs-keyword\">let<\/span> { items, onSelect }: Props&lt;T&gt; = $props();\n  <span class=\"hljs-comment\">\/\/         Error here _________^<\/span>\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The first&nbsp;<code>T<\/code>&nbsp;is a generic&nbsp;<em>parameter<\/em>, which is defined as part of the&nbsp;<code>Props<\/code>&nbsp;type. This is fine. The problem is, we need to instantiate that generic type with an actual value for T when we attempt to use it in the destructuring. The&nbsp;<code>T<\/code>&nbsp;that I used there is undefined. It doesn&#8217;t exist. TypeScript has no idea what that&nbsp;<code>T<\/code>&nbsp;is because it hasn&#8217;t been defined.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"what-changed\">What changed?<\/h3>\n\n\n\n<p>Why did this work so easily with React? The reason is, React components are&nbsp;<em>functions<\/em>. You can define a generic function, and when you&nbsp;<em>call it<\/em>&nbsp;TypeScript will&nbsp;<em>infer<\/em>&nbsp;(if it can) the values of its generic types. It does this by looking at the arguments you pass to the function. With React,&nbsp;<em>rendering<\/em>&nbsp;a component is conceptually the same as calling it, so TypeScript is able to look at the various props you pass, and infer the generic types as needed.<\/p>\n\n\n\n<p>Svelte components are not functions. They&#8217;re a proprietary bit of code thrown into a <code>.svelte<\/code> file that the Svelte compiler turns into something useful. We do still render Svelte components, and TypeScript could easily look at the props we pass, and infer back the generic types as needed. The root of the problem, though, is that we haven&#8217;t (yet) declared any generic types that are associated with the&nbsp;<em>component itself<\/em>. With React components, these are the same generic types we declare for any function. What do we do for Svelte?<\/p>\n\n\n\n<p>Fortunately, the Svelte maintainers thought of this. You can declare generic types for the component itself with the&nbsp;<code>generics<\/code>&nbsp;attribute on the&nbsp;<code>&lt;script&gt;<\/code>&nbsp;tag at the top of your Svelte component:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span> <span class=\"hljs-attr\">generics<\/span>=<span class=\"hljs-string\">\"T\"<\/span>&gt;<\/span><span class=\"javascript\">\n  type Props&lt;T&gt; = {\n    <span class=\"hljs-attr\">items<\/span>: T&#91;];\n    onSelect: <span class=\"hljs-function\">(<span class=\"hljs-params\">item: T<\/span>) =&gt;<\/span> <span class=\"hljs-keyword\">void<\/span>;\n  };\n\n  <span class=\"hljs-keyword\">let<\/span> { items, onSelect }: Props&lt;T&gt; = $props();\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You can even define constraints on your generic arg:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span> <span class=\"hljs-attr\">generics<\/span>=<span class=\"hljs-string\">\"T extends { name: string }\"<\/span>&gt;<\/span><span class=\"javascript\">\n  type Props&lt;T&gt; = {\n    <span class=\"hljs-attr\">items<\/span>: T&#91;];\n    onSelect: <span class=\"hljs-function\">(<span class=\"hljs-params\">item: T<\/span>) =&gt;<\/span> <span class=\"hljs-keyword\">void<\/span>;\n  };\n\n  <span class=\"hljs-keyword\">let<\/span> { items, onSelect }: Props&lt;T&gt; = $props();\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>TypeScript will enforce this. If you violate that constraint like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"javascript\">\n  <span class=\"hljs-keyword\">import<\/span> AutoComplete <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/AutoComplete.svelte\"<\/span>;\n\n  <span class=\"hljs-keyword\">let<\/span> items = &#91;{ <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Adam\"<\/span> }, { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Rich\"<\/span> }];\n  <span class=\"hljs-keyword\">let<\/span> onSelect = <span class=\"hljs-function\">(<span class=\"hljs-params\">item: { id: number }<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-built_in\">console<\/span>.log(item.id);\n  };\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">AutoComplete<\/span> {<span class=\"hljs-attr\">items<\/span>} {<span class=\"hljs-attr\">onSelect<\/span>} \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>TypeScript will let you know:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Type '(item: { id: number; }) =&gt; void' is not assignable to type '(item: { name: string; }) =&gt; void'. Types of parameters 'item' and 'item' are incompatible.<br><br>Property 'id' is missing in type '{ name: string; }' but required in type '{ id: number; }'.<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"effects\">Effects<\/h2>\n\n\n\n<p>Let&#8217;s wrap up with something comparatively easy: side effects. As we saw before, briefly, in Svelte 4 you could run code for side effects inside of&nbsp;<code>$:<\/code>&nbsp;reactive blocks<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">$: {\n  <span class=\"hljs-built_in\">console<\/span>.log(someStateValue1, someStateValue2);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That code would re-run when either of those values changed.<\/p>\n\n\n\n<p>Svelte 5 introduces the&nbsp;<code>$effect<\/code>&nbsp;rune. This will run after state has changed, and been applied to the dom. It is for&nbsp;<em>side effects<\/em>. Things like resetting the scroll position after state changes. It is&nbsp;<em>not<\/em>&nbsp;for synchronizing state. If you&#8217;re using the&nbsp;<code>$effect<\/code>&nbsp;rune to synchronize state, you&#8217;re probably doing something wrong (the same goes for the&nbsp;<code>useEffect<\/code>&nbsp;hook in React).<\/p>\n\n\n\n<p>The code is pretty anti-climactic.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">$effect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">\"Current count is \"<\/span>, count);\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>When this code first starts, and anytime count changes, you&#8217;ll see this log. To make it more interesting, let&#8217;s pretend we have a current timestamp value that auto-updates:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> timestamp = $state(+<span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Date<\/span>());\nsetInterval(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  timestamp = +<span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Date<\/span>();\n}, <span class=\"hljs-number\">1000<\/span>);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We want to include that value when we log, but we&nbsp;<em>don&#8217;t<\/em>&nbsp;want our effect to run whenever our timestamp changes; we only want it to run when count changes. Svelte provides an&nbsp;<code>untrack<\/code>&nbsp;utility for that<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-29\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> { untrack } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"svelte\"<\/span>;\n\n$effect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">let<\/span> timestampValue = untrack(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> timestamp);\n  <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">\"Current count is \"<\/span>, count, <span class=\"hljs-string\">\"at\"<\/span>, timestampValue);\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-29\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\" id=\"interop\">Interop<\/h2>\n\n\n\n<p>Massive upgrades where an entire app is updated to use a new framework version&#8217;s APIs are seldom feasible, so it should come as no surprise that Svelte 5 continues to support Svelte 4. You can upgrade your app incrementally. Svelte 5 components can render Svelte 4 components, and Svelte 4 components can render Svelte 5 components. The one thing you can&#8217;t do is mix and match within a single component. You cannot use reactive assignments&nbsp;<code>$:<\/code>&nbsp;in the same component that&#8217;s using Runes (the Svelte compiler will remind you if you forget).<\/p>\n\n\n\n<p>Since stores are not yet deprecated, they can continue to be used in Svelte 5 components. Remember the&nbsp;<code>createNumberInfo<\/code>&nbsp;method from before, which returned an object with a store on it? We can use it in Svelte 5. This component is perfectly valid, and works.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-30\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span>&gt;<\/span><span class=\"javascript\">\n  <span class=\"hljs-keyword\">import<\/span> { createNumberInfo } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/svelte4\/numberInfoStore'<\/span>;\n\n  <span class=\"hljs-keyword\">const<\/span> numberPacket = createNumberInfo(<span class=\"hljs-number\">0<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> store = numberPacket.numberInfo;\n  <span class=\"hljs-keyword\">let<\/span> junk = $state(<span class=\"hljs-string\">'Hello'<\/span>);\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>Run value: {junk}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>Number value: {$store.value}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onclick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> numberPacket.update($store.value + 1)}&gt;Update<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-30\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>But the rule against reactive assignments still holds; we cannot use one to destructure values off of stores when we&#8217;re in Svelte 5 components. We&nbsp;<em>have to<\/em>&nbsp;&#8220;dot through&#8221; to nested properties with things like&nbsp;<code>{$store.value}<\/code>&nbsp;in the binding (which always works) rather than:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">$: ({ value } = $store);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-31\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>&#8230; which generates the error of:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><code>$:<\/code>&nbsp;is not allowed in runes mode, use&nbsp;<code>$derived<\/code>&nbsp;or&nbsp;<code>$effect<\/code>&nbsp;instead<\/p>\n<\/blockquote>\n\n\n\n<p>The error is even clear enough to give you another alternative to inlining those nested properties, which is to create a&nbsp;<code>$derived<\/code>&nbsp;state:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-32\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">let<\/span> value = $derived($store.value);\n<span class=\"hljs-comment\">\/\/ or let { value } = $derived($store);<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-32\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Personally I&#8217;m not a huge fan of mixing the new&nbsp;<code>$derived<\/code>&nbsp;primitive with the old Svelte 4 syntax of&nbsp;<code>$store<\/code>, but that&#8217;s a matter of taste.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"parting-thoughts\">Parting thoughts<\/h2>\n\n\n\n<p>Svelte 5 has shipped some incredibly exciting changes. We covered the new, more reliable reactivity primitives, the improved prop management with tighter TypeScript integration, and the new side effect primitive. But we haven&#8217;t come closing to covering everything. Not only are there more variations on the&nbsp;<code>$state<\/code>&nbsp;rune, but Svelte 5 also updated it&#8217;s event handling mechanism, and even shipped an exciting new way to re-use &#8220;snippets&#8221; of HTML.<\/p>\n\n\n\n<p>Svelte 5 is worth a serious look for your next project.<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/introducing-svelte-5\/\">Introducing Svelte 5<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/snippets-in-svelte-5\/\">Snippets in Svelte 5<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/fine-grained-reactivity-in-svelte-5\/\">Fine-Grained Reactivity in Svelte 5<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Svelte 5 introduces significant improvements in reactivity, state management, and prop handling, maintaining its user-friendly Developer Experience (DX). <\/p>\n","protected":false},"author":21,"featured_media":3091,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[3,161],"class_list":["post-3067","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-javascript","tag-svelte"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-18-at-3.03.18%E2%80%AFPM.png?fit=1890%2C1122&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3067","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=3067"}],"version-history":[{"count":18,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3067\/revisions"}],"predecessor-version":[{"id":3445,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3067\/revisions\/3445"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/3091"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=3067"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=3067"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=3067"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}