如何在 Svelte 中创建一个可在所有页面中使用的上下文?

How to create a context that can be used in all pages in Svelte?

我目前正在学习 Svelte,我想为这个副项目创建一个身份验证流程。通常,在 React 中,我习惯使用 Contexts 保存身份验证信息。

<AuthContext>
   <App />
<AuthContext>

我想知道 Svelte 是否也可以执行类似的方法?所有教程都是基于组件的上下文。我想在我的整个应用程序中调用 getContext('authContext')。

AuthContext.svelte

<script lang='ts'>
      import { writable } from 'svelte/store'
      import { onDestroy, setContext } from 'svelte'
      import {getAuth, type User, onAuthStateChanged} from 'firebase/auth'
    
      const auth = getAuth()
      const userStore = writable<User | null>(null)
      const isLoggedIn = writable<boolean>(false)
      
      const contexts = {
        isLoggedIn,
        userStore,
        logOut,
      }
      
      const unsubscribe =  onAuthStateChanged(auth, (user) => {
        if(user) {
          userStore.set(user)
          isLoggedIn.set(true)
        }
      })

      setContext('authContext', contexts)
 
    function logOut() {
      auth.signOut()
      isLoggedIn.set(false)
    }
    
    
      onDestroy(() => unsubscribe())
    
</script>
    

我在 __layout.svelte 中调用了 getContext:

<script lang='ts'>
      import {getContext} from 'svelte'

      const {isLoggedIn} = getContext('authContext')
      
</script>

它产生这个错误:

Cannot destructure property 'isLoggedIn' of '__vite_ssr_import_1__.getContext(...)' as it is undefined.

不确定这是否必须通过 SvelteKit 中的组件来完成?上下文不能这样构建和设置吗? REPL
(我过去常常在没有上下文的情况下这样做 REPL

App.svelte
<script>
    import { setContext } from 'svelte'
    import {authContext} from './authContext'
    import Component from './Component.svelte'

    setContext('authContext', authContext)
</script>

<Component />
authContext.js
import { writable } from 'svelte/store'
import {getAuth, onAuthStateChanged} from 'firebase/auth'

const auth = getAuth()

const userStore = writable(null)
const isLoggedIn = writable(false)

onAuthStateChanged(auth, (user) => {
    if(user) {
        userStore.set(user)
        isLoggedIn.set(true)
    }else {
        userStore.set(null)
        isLoggedIn.set(false)
    }
})

async function logOut() {
    await auth.signOut()
//  isLoggedIn.set(false) // (would handle via onAuthStateChanged) 
}

export const authContext = {
    isLoggedIn,
    userStore,
    logOut,
}
Component.svelte
<script>
    import {getContext} from 'svelte'
    const {isLoggedIn, userStore, logOut} = getContext('authContext')
    
    async function handleLogout(){
        try{
            await logOut()
        }catch(error){
            console.error(error)
        }
    }
</script>

<div>
    isLoggedIn: {$isLoggedIn}<br>
    username:
    {#if $isLoggedIn}
        {$userStore.username}
    {/if}
</div>

<button on:click={handleLogout}>
    logOut
</button>

<style>
    button {
        margin-top: 1rem;
    }
</style>

要在所有页面中使用'context',您应该只使用普通商店。

在外部 javascript 文件中定义商店:

// ./stores.js
import { writable } from 'svelte/store';

export const loggedIn = writable(false);
export const user = writable(null);

并在必要时简单地导入它:

<!-- Component.svelte -->
<script>
  import { loggedIn } from './stores.js';
</script>