SVELTE: неперехваченный (в обещании) Ошибка типа: не удается прочитать свойство ‘profile’

#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>