问题
helo :)
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>
What am I doing wrong?
回答1:
setContext
must be called synchronously during component initialization. That is, from the root of the <script>
tag:
<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>
This is mentioned in a little cryptic sentence in the docs:
Like lifecycle functions, this must be called during component initialisation.
Other lifecycle functions are onMount
, onDestroy
, etc. It is arguably less obvious that setContext
is such a lifecycle method.
Edit
I just reread your question, and realized this really just answer half of it...
setContext
/ getContext
can only be used once at component init, so how do you share your API result through context? Related: how would you share those API results if the call was made outside of a Svelte component, where setContext
would be even more out of the question (and the API call would arguably be better located, for separation of concerns matters)?
Well, put a store in your context.
For example, with a writable store:
<script>
import { getContext } from 'svelte'
const userData = getContext('userData')
function handleRegistration(e) {
doSuperApiCall()
.then(data => {
userData.set(data)
// or fancy:
$userData = data
})
.catch(...)
}
</script>
...
Put this store in context during the init of some higher wrapping component (the like of <App>
):
<script>
import { setContext } from 'svelte'
import { writable } from 'svelte/store'
const userData = writable(null)
setContext('userData', userData)
</script>
<slot />
This way you can easily access your store with getContext
from any child component of (say) <App>
, and read to / write from it asynchrnously.
来源:https://stackoverflow.com/questions/60591927/svelte-user-registration-issue-with-setting-store-value