DEV Community

Cover image for Svelte Series-7: The Syntax $
Garlic Garlic
Garlic Garlic

Posted on

Svelte Series-7: The Syntax $

If you have used Vue or React, then must know about APIs such as Vue's computed, watch, and React's useMemo, which are used to monitor certain variables and recalculate new variables or execute certain methods only after changes occur.

In Svelte, a similar functionality is also provided. Svelte calls it Reactivity. The core that triggers the responsive capability is - assignment. The specific writing is as follows:

$: Your logic
Enter fullscreen mode Exit fullscreen mode

Perhaps everyone will be curious about what the $ syntax is. In fact, it is a syntax normally supported by js, the JS label syntax, but few people use it and it is equivalent to an almost obsolete syntax.

By using $: as a prefix, Svelte can make any statement at the top-level (that is, not inside a block or function) reactive. Whenever the values they depend on change, they will run immediately before the component is updated.

Declaration

$: syntax

If a statement consists entirely of assignments to undeclared variables, Svelte inserts the let declaration for you.

<script>
  let count = 0;

  $: double = count * 2;

  let noReactiveDouble = count * 2;

  const add = () => {
    count++;
  }
</script>

<button on:click={add}>add</button><br>
count: {count}<br>
doubleCount: {double}<br>
noReactiveDouble: {noReactiveDouble}
Enter fullscreen mode Exit fullscreen mode

We don't need to declare let double. In $: double = count * 2;, it's equivalent to Svelte automatically declaring it for us.

Statement

We add a line in the above code:

$: console.log('$ console', count, double, noReactiveDouble);
Enter fullscreen mode Exit fullscreen mode

The changes of each state can be observed intuitively. The variable double declared in $: will change with the change of count, while the variable noReactiveDouble declared outside $: remains 0 even if count changes because the initial count is 0.

The difference from beforeUpdate

<script>
  import { beforeUpdate } from 'svelte';

  let count = 0;
  let noReactiveDouble = count * 2;

  const add = () => {
    count++;
  }

  $: console.log('$ console', noReactiveDouble);

  beforeUpdate(() => {
    console.log('beforeUpdate console', noReactiveDouble)
  })
</script>

<button on:click={add}>add</button><br>
count: {count}<br>
noReactiveDouble: {noReactiveDouble}
Enter fullscreen mode Exit fullscreen mode

When we refresh the page again, we can see that in $, it is executed once, and beforeUpdate is also executed once. Because let noReactiveDouble = count * 2 is an assignment operation, $: console.log('$ console', noReactiveDouble); is triggered at the first assignment; while beforeUpdate is due to the assignment operations of the two variables count and noReactiveDouble. When we click to update, because noReactiveDouble is not a reactive variable, only beforeUpdate is triggered.

The logic within the $ statement is only executed when the variables within the statement trigger an update. While beforeUpdate is equivalent to collecting all variable dependencies. It is executed when one of the dependencies changes.

The statement can not only be written in a single line like $: console.log(), but also can be wrapped in a {} curly brace.

$: {
  // your logic
}
Enter fullscreen mode Exit fullscreen mode

We have learned that Svelte can automatically declare variables that are not declared using the let statement. The expression $: double = count * 2; is equivalent to the following writing.:

let double;
$: {
  double = count * 2;
}
Enter fullscreen mode Exit fullscreen mode

Therefore, when we use {}, we still need to declare it ourselves:

<script>
  let count = 0;
  $: double = count * 2;
  let double2;

  $: {
    double2 = count * 2;
  }

  const add = () => {
    count++;
  }
</script>

<button on:click={add}>add</button><br>
count: {count}<br>
doubleCount: {double}<br>
double2: {double2}
Enter fullscreen mode Exit fullscreen mode

Dependency

When we are using $: {} for some complex reactive operations, a situation may arise. We only want our code to execute when a certain variable changes, rather than every time any variable in the code changes. For example:

<script>
  let width = 1;
  let height = 1;

  $: area = width * height;
</script>

width: <input type="number" bind:value={width} /><br />
height: <input type="number" bind:value={height} /><br />
area: {area}
Enter fullscreen mode Exit fullscreen mode

Whenever the width or height changes, area = width * height is executed. Is there any way to execute only when the width changes and not when the height changes?

In fact, the trick lies in moving the dependencies that you don't want to listen to out of $:.

<script>
  let width = 1;
  let height = 1;

  function setArea(width) {
    return width * height;
  }

  $: area = setArea(width);
</script>

width: <input type="number" bind:value={width} /><br />
height: <input type="number" bind:value={height} /><br />
area: {area}
Enter fullscreen mode Exit fullscreen mode

Within $:, there is only the width variable. When the width changes, setArea() is executed. However, the height is not within $:. Even if the height changes, no reactive update is performed.

Summary

In this chapter, we have learned:

  • The use of the $syntax in Svelte. Through $, we can implement computed properties and also listen for variable updates to perform certain operations.
  • The difference between $ and beforeUpdate lifecycle functions

Top comments (0)