I am trying to change component once the user is logged in, but so far I am not able to do this. Once I make successful login, component remains the same.
I have App.svelte component:
<script>
import { fade } from 'svelte/transition'
import { currentComponent } from './store/view.svelte';
const loadComponent = currentComponent()
$effect(() => {
console.log(loadComponent);
})
</script>
<div id="viewport" transition:fade>
<svelte:component this={loadComponent.component}></svelte:component>
</div>
Login.svelte component
<script>
import { currentComponent } from "../store/view.svelte";
let email = $state('')
let password = $state('')
let test = currentComponent()
/**
* @param {{ preventDefault: () => void; }} event
*/
async function submit(event){
event.preventDefault()
fetch('http://localhost:9555/api/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json; charset=UTF-8',
},
body: JSON.stringify({
email,
password
})
})
.then(resp => resp.json())
.then(json => {
localStorage.setItem('_token', json.token)
test.updateComponent()
})
}
</script>
<div
class="relative mx-auto w-full max-w-md bg-white px-6 pt-10 pb-8 shadow-xl ring-1 ring-gray-900/5 sm:rounded-xl sm:px-10">
<div class="w-full">
<div class="text-center">
<h1 class="text-3xl font-semibold text-gray-900">Sign in</h1>
<p class="mt-2 text-gray-500">Sign in below to access your account</p>
</div>
<div class="mt-5">
<form action="" onsubmit="{submit}">
<div class="relative mt-6">
<input
bind:value={email}
placeholder="Email Address"
class="peer mt-1 w-full border-b-2 border-gray-300 px-0 py-1 placeholder:text-transparent focus:border-gray-500 focus:outline-none"
autocomplete="NA" />
<label for="email" class="pointer-events-none absolute top-0 left-0 origin-left -translate-y-1/2 transform text-sm text-gray-800 opacity-75 transition-all duration-100 ease-in-out peer-placeholder-shown:top-1/2 peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-500 peer-focus:top-0 peer-focus:pl-0 peer-focus:text-sm peer-focus:text-gray-800">Email Address</label>
</div>
<div class="relative mt-6">
<input type="password" name="password" id="password"
bind:value={password}
placeholder="Password" class="peer peer mt-1 w-full border-b-2 border-gray-300 px-0 py-1 placeholder:text-transparent focus:border-gray-500 focus:outline-none" />
<label for="password" class="pointer-events-none absolute top-0 left-0 origin-left -translate-y-1/2 transform text-sm text-gray-800 opacity-75 transition-all duration-100 ease-in-out peer-placeholder-shown:top-1/2 peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-500 peer-focus:top-0 peer-focus:pl-0 peer-focus:text-sm peer-focus:text-gray-800">Password</label>
</div>
<div class="my-6">
<button type="submit" class="w-full rounded-md bg-black px-3 py-4 text-white focus:bg-gray-600 focus:outline-none">Sign in</button>
</div>
<p class="text-center text-sm text-gray-500">Don't have an account yet?
<a href="#!"
class="font-semibold text-gray-600 hover:underline focus:text-gray-800 focus:outline-none">Sign
up
</a>.
</p>
</form>
</div>
</div>
</div>
view.svelte.js:
import Restaurant from "../routes/Restaurant.svelte";
import Login from '../routes/Login.svelte';
export function currentComponent(){
const _token = localStorage.getItem('_token')
let authorized = $state(_token ? true : false)
let component = $derived(!authorized ? Login : Restaurant)
function updateComponent(){
authorized = true
}
return {
get authorized(){
return authorized
},
set authorized(newValue){
authorized = newValue
},
get component(){
return component
},
updateComponent
}
}
Once I update authorized (test.updateComponent() call), the component is updated in view.svelte.js but the new component is not rendered. What am I doing wrong here?
You are not changing the same instance, hence nothing happens.
You could e.g. do either of
Make currentComponent
a singleton, e.g.
function createCurrentComponent() {
// [old code]
}
export const currentComponent = createCurrentComponent();
(Of course you then would not call currentComponent
any more.)
Create one instance at the root component and pass that around, e.g. via a context.
Also, for the fade to work, you would need something like this:
<div class="stack">
{#key loadComponent.component}
<div id="viewport" transition:fade>
<svelte:component this={loadComponent.component} />
</div>
{/key}
</div>
<style>
.stack { display: grid }
.stack > * { grid-area: 1 / 1 }
</style>