设置存储值的 Svelte 用户注册问题

toH*_*oHo 2 svelte svelte-store

你好:)

I'm trying to register an user and after success, setContext to newly registered user and then navigate to home. Server properly responds and registers user, but when setContext is called i get the following error: "index.mjs:552 Uncaught (in promise) Error: Function called outside component initialization"

    <script>
    import { setContext } from 'svelte'

    async function handleRegistration(e) {
        let user = {
                    firstname: e.target.firstname.value,
                    lastname: e.target.lastname.value,
                }

                fetch('http://localhost:3001/api/auth/register', {
                    method: 'POST',
                    headers: {'Content-Type':'application/json'},
                    body: JSON.stringify(user)
                })
                .then(res => res.json())
                .then(res => {
                    if(res.accessToken) {
                        user.accessToken = res.accessToken
                        user.refreshToken = res.refreshToken
                        setContext('userData', user)
                        navigate("/", { replace: true })
                    }
                })

                updateContext(user)
            }
    }
</script>

<form class="registration" on:submit|preventDefault="{handleRegistration}">
</form>
Run Code Online (Sandbox Code Playgroud)

What am I doing wrong?

rix*_*ixo 7

setContext必须在组件初始化期间同步调用。也就是说,从<script>标签的根开始:

<script>
  import { setContext } from 'svelte'

  console.log('init')

  setContext(...) // OK

  setTimeout(() => {
    setContext(...) // Not OK (we're not synchronous anymore)
  }, 0)
<script>

<h1>My Svelte Component</h1>
Run Code Online (Sandbox Code Playgroud)

这在文档中的一个小神秘句子中提到:

与生命周期函数一样,必须在组件初始化期间调用它。

其他生命周期函数是onMountonDestroy等。可以说,setContext这种生命周期方法不太明显。

编辑

我刚刚重读了你的问题,并意识到这真的只是回答了一半......

setContext/getContext只能在组件初始化时使用一次,那么如何通过上下文共享 API 结果呢?相关:如果调用是在 Svelte 组件之外进行的,您将如何共享这些 API 结果,哪里setContext更不可能(并且可以说 API 调用可以更好地定位,因为关注点分离问题)?

好吧,将商店放在您的上下文中。

例如,对于可写存储:

<script>
  import { getContext } from 'svelte'

  const userData = getContext('userData')

  function handleRegistration(e) {
    doSuperApiCall()
      .then(data => {
        userData.set(data)
        // or fancy:
        $userData = data
      })
      .catch(...)
  }
</script>
...
Run Code Online (Sandbox Code Playgroud)

在一些更高的包装组件(例如<App>)的初始化期间将此存储置于上下文中:

<script>
  import { setContext } from 'svelte'
  import { writable } from 'svelte/store'

  const userData = writable(null)

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

<slot />
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以getContext从 (say) 的任何子组件轻松访问您的商店<App>,并异步读取/写入它。