#javascript #promise #svelte
#javascript #обещание #стройный
Вопрос:
Я использую Svelte в течение одной недели, и после аутентификации в моем приложении с помощью cidaas-sdk данные профиля не отображаются через несколько секунд. Страница застряла «… ожидание», и эта ошибка в консоли Uncaught (in promise) TypeError: Cannot read property 'profile' of undefined at Array.create_if_block$1 at create_then_block$2
Проблема здесь в том, что мне нужно обновить страницу, чтобы отобразить данные.
Моя проблема в том, что я не могу получить {userInfo.profile.given_name}
данные непосредственно после входа в систему, поэтому бесполезно перезагружать страницу для отображения данных. Но когда страница перезагружается, все в порядке, сообщений об ошибках в консоли нет.
import cidaas from './helpers/cidaas';
import Profile from './components/profile.svelte';
import { onMount } from 'svelte';
export let title;
$ : isAuth = false;
$ : isLoaded = false;
let promiseHome = Promise.resolve([]);
onMount(async () => {
promiseHome = cidaas.getUserInfo();
promiseHome.then(userInfo => {
if(!userInfo) {
// if you are logged
if (window.location.href.includes("grant_type=login")) {
cidaas.loginCallback();
window.history.replaceState("", "", "/");
isAuth = true;
isLoaded = true;
return;
}
}
isAuth = !!userInfo;
isLoaded = true;
return;
})
});
HTML-часть :
{#await promiseHome}
<div class="mt-5">...Waiting</div>
{:then userInfo}
{#if isAuth == true}
<div class="jumbotron col-md-8 mx-auto">
<div class="hello mt-5 mb-3">Hello {userInfo.profile.given_name}!</div>
<p>isAuth : {isAuth}</p>
<p>isLoaded : {isLoaded}</p>
</div>
<Profile/>
{:else}
<h1 class="mt-5">Bienvenue sur {title}</h1>
<p>isAuth : {isAuth}</p>
<p>isLoaded : {isLoaded}</p>
<button class="btn btn-primary btn-mdir" on:click={loginTo}>Se connecter</button>
<button class="btn btn-primary btn-mdir" on:click={register}>S'inscrire</button>
{/if}
{:catch error}
<p>{error.message}</p>
{/await}
Комментарии:
1. Можете ли вы сделать минимальное воспроизведение в Svelte REPL ? Я не уверен, что
cidaas.getUserInfo()
возвращает.
Ответ №1:
Я не в Svelte, но после первого взгляда на ваше описание — можете ли вы проверить реализацию вашего cidaas.loginCallback()
метода. Это метод Promise и требует await
. Может быть причина в том, что в первый раз он не работает, и после обновления он работает.
Ответ №2:
Это бесполезно:
$: isAuth = false;
Реактивные блоки пересчитываются, когда изменяется любая переменная, которую они содержат, но переменная не должна быть объявлена в реактивном блоке, чтобы быть реактивной.
Любая let
переменная верхнего уровня является реактивной.
<script>
let a // reactive
const b = 0 // not reactive
{
let c // not reactive
}
function foo() {
let d // not reactive
}
</script>
Итак, let isAuth = false
достаточно просто, и все равно будет реактивным (и сэкономит Svelte некоторую работу, потому что реактивные блоки — это более сложный механизм, чем просто отслеживание одной переменной).
Теперь, к вашей проблеме…
Сбой происходит в вашем then
блоке, когда обещание разрешается undefined
следующим образом: userInfo.profile.given_name
.
Я не понимаю всю вашу логику загрузки, поэтому, если бы мне пришлось исправить этот код прямо сейчас, я бы заменил это:
{:then userInfo}
{#if isAuth == true}
с помощью этого:
{:then userInfo}
{#if userInfo amp;amp; isAuth == true}
Ответ №3:
Теперь мое приложение работает с :
<script>
import cidaas from './helpers/cidaas';
import Profile from './components/profile.svelte';
import { onMount } from 'svelte';
export let title;
let state = {
isAuth: false,
isLoaded: false,
sUserProfile: {}
}
onMount(async () => {
cidaas.getUserInfo()
.then(userInfo => {
if(!userInfo) {
// if you are logged out
if (!window.location.href.includes("grant_type") amp;amp; window.location.href.includes("state")) {
cidaas.logoutCallback();
window.history.replaceState("", "", "/");
state.isAuth = false;
}
// if you are logged
if (window.location.href.includes("grant_type=login")) {
cidaas.loginCallback()
.then(response => {
state.sUserProfile = response.profile;
state.isAuth = true;
window.history.replaceState("", "", "/");
});
}
} else {
state.sUserProfile = userInfo.profile;
state.isAuth = true
}
state.isLoaded = true;
})
});
function logout() {
cidaas.logout();
}
function loginTo() {
cidaas.loginWithBrowser();
}
function register() {
cidaas.registerWithBrowser();
}
</script>
HTML :
<header>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand text-white" href="http://localhost:5000"><img class="logo" src="mdir-white.png" alt="mdir_logo"></a>
</div>
<ul class="nav navbar-nav">
</ul>
{#if state.isAuth == true}
<ul class="nav navbar-nav navbar-right">
<li><button class="btn btn-primary btn-mdir" on:click={logout}>Logout</button></li>
</ul>
{/if}
</div>
</nav>
</header>
<main>
{#if state.isLoaded}
{#if !state.isAuth}
<h1 class="mt-5">Bienvenue sur {title}</h1>
<p>isAuth : {state.isAuth}</p>
<p>isLoaded : {state.isLoaded}</p>
<button class="btn btn-primary btn-mdir" on:click={loginTo}>Se connecter</button>
<button class="btn btn-primary btn-mdir" on:click={register}>S'inscrire</button>
{:else}
<div class="jumbotron col-md-8 mx-auto">
<div class="hello mt-5 mb-3">Hello {state.sUserProfile.given_name}!</div>
<p>isAuth : {state.isAuth}</p>
<p>isLoaded : {state.isLoaded}</p>
</div>
<Profile/>
{/if}
{:else}
<div>...PROBLEM AUTH</div>
{/if}
</main>