Horst
Horst

Reputation: 259

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?

Upvotes: 3

Views: 3817

Answers (1)

Stephane Vanraes
Stephane Vanraes

Reputation: 16411

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}

Upvotes: 8

Related Questions