Introduction to Reactive Side Effects
Understanding the `$effect` Rune
Using `$effect` for Cleanup

When using $effect, it’s important to clean up after yourself to avoid memory leaks or unexpected behavior. For example, if you set up a timer using setInterval, you should clear it when it’s no longer needed. Here’s how you can do that:

<script>
    let timeLeft = $state(10);
    let running = $state(false);

    $effect(() => {
        if (!running) return;

        const id = setInterval(() => {
            if (timeLeft > 0) {
                timeLeft -= 1;
            } else {
                running = false;
            }
        }, 1000);

        return () => {
            clearInterval(id); // Cleanup the interval
        };
    });
</script>

<button onclick={() => running = true}>Start</button>
<button onclick={() => running = false}>Stop</button>
<p>Time left: {timeLeft}</p>

In this example, the $effect rune sets up a timer that counts down from 10. When the timer is no longer needed (e.g., when the user clicks “Stop”), the cleanup function (clearInterval) is called to stop the timer. This ensures that your application doesn’t waste resources or behave unexpectedly.

Cleanup is a crucial part of using $effect, and it’s something you’ll need to consider whenever you’re managing side effects. In the next section, we’ll explore how to use the untrack function to avoid unnecessary re-runs.

Combining `$effect` with `untrack`
Building the Countdown Timer

Now that you understand the basics of $effect and untrack, let’s build a complete countdown timer. Here’s the code we’ll be working with:

<script>
    let timeLeft = $state(10);
    let running = $state(false);
    let startCount = $state(0);

    $effect(() => {
        if (!running) return;

        const id = setInterval(() => {
            if (timeLeft > 0) {
                timeLeft -= 1;
            } else {
                running = false;
            }
        }, 1000);

        return () => {
            clearInterval(id);
        };
    });

    $effect(() => {
        if (running) {
            untrack(() => {
                startCount++;
            });
        }
    });
</script>

<h3>Countdown Timer</h3>
<button onclick={() => running = true}>Start</button>
<button onclick={() => running = false}>Stop</button>
<button onclick={() => { timeLeft = 10; running = false; }}>Reset</button>
<p>Time left: {timeLeft}</p>
<p>Total starts: {startCount}</p>

This code creates a countdown timer that starts at 10 seconds. The $effect rune manages the timer, and the untrack function increments the startCount variable without triggering a re-run. The timer can be started, stopped, and reset using the buttons.

When you run this code, you’ll see the timer count down from 10, and the “Total starts” counter will increase each time you start the timer. This example demonstrates how to use $effect and untrack together to manage side effects and state in a Svelte application.

Below is a preview of how the timer will look when running:

Best Practices for `$effect` in Svelte
Summary and Next Steps
Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal