Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Svelte: make component reactive to variable (rerender)

I want to rerender "Body" (my svelte component) whenever "view.current" changes so it renders the corresponding .svelte view/component:

App.svelte

    <script>
    import Header from "./components/Header.svelte";
    import Footer from "./components/Footer.svelte";
    import Body from "./components/Body.svelte";

    import Login from "./views/Login.svelte";
    import Dashboard from "./views/Dashboard.svelte";

    import { view } from "./store";
</script>

<Header />
    <Body>
        {#if view.current === view.login}
            <Login />
        {:else if view.current === view.dashboard}
            <Dashboard />
        {/if}
    </Body>
<Footer />

In "Body.svelte" i just have a slot that gets styled

Body.svelte

    <div class="container">
    <div class="content">
        <slot></slot>
    </div>
</div>

<style>
    .container {
        padding: 1em;
        display: flex;
    }
    .content {
        margin: auto;
    }
</style>

In Login.svelte (and other svelte components) i want to change "view.current":

Login.svelte

<script>
    import { view } from "../store";

    function handleLoginClick() {
        view.current = view.dashboard;
    }
</script>


<button type="button" on:click={handleLoginClick} class="btn btn-primary btn-lg login-btn">Login</button>

<style>
    .login-btn {
        display: block;
        margin: auto;
    }
</style>

store.js

    const user = {
    username: "",
    fullname: "",
    role: null,
    isLoggedIn: false
};

const view = {
    login: 1,
    dashboard: 2,
    current: 1
};

export {
    user,
    view
}

The value of "view.current" changes as expected, however "Body" does not update/rerender. So it always shows the login.svelte no matter to what "view.current" has been set. Is there a quick and easy way to make "Body" reactive to "view.current" so that it rerenders so that the if/else-block in "App.svelte" get's reevaluated?

like image 745
Horst Avatar asked Mar 05 '26 03:03

Horst


1 Answers

Importing a regular variable like that in a component creates a local copy of said variable. The view you are referring to in the Login is not shared with the one in App, so the changes are not reflected there.

The "Svelte-way" of sharing state like that accross components is to use a store.

In your setup that would mean you define view as a store first:

import { writable } from 'svelte/store'

const view = writable({
    login: 1,
    dashboard: 2,
    current: 1
});

In the components themselves you have to prefix the store with $

<script>
    function handleLoginClick() {
        $view.current = $view.dashboard;
    }
</script>
{#if $view.current === $view.login}
    <Login />
{:else if $view.current === $view.dashboard}
    <Dashboard />
{/if}
like image 56
Stephane Vanraes Avatar answered Mar 07 '26 16:03

Stephane Vanraes



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!