2016-08-03 26 views
0

我正在構建使用模型,服務和自定義元素的Aurelia框架的相當先進的應用程序。對象的引用以某種方式丟失

我有一個用戶模型包含用戶名,電子郵件等以及bool isLoggedIn。

我有一個存儲用戶在localStorage的用戶服務,讓您更新用戶數據等等等等

我終於有使用用戶服務的一些自定義元素,以獲取當前用戶,並顯示UI這取決於用戶是否登錄。

我面臨的問題是,在使用用戶服務提取用戶後,從我的一個自定義元素(存儲在用戶服務中)更新用戶模型後,另一個自定義元素對所述用戶的引用型號不會更新。

我試着在JSFiddle中複製這個問題(在普通的JS中 - 我正在寫這個在ES6中),但沒有這樣做,在小提琴中的所有工作正常。

這裏有很多代碼,但我想聽聽您的意見,我可能會爲此發生什麼錯誤?

這裏是我有什麼要點:

user.model.js

export class User { 
    username = ''; 
    isLoggedIn = false; 

    constructor (data) { 
     Object.assign(this, data); 
    } 
} 

user.service.js

import { User } from 'user.model'; 

export class UserService { 
    constructor() { 
     this.user = null; 
    } 

    getUser() { 
     // User is cached 
     if (this.user) { 
      return Promise.resolve(this.user); 
     } 

     // Check if we have localStorage 
     var user = window.localStorage.getItem('user'); 

     if (user) { 
      this.user = new User(JSON.parse(user)); 

      return Promise.resolve(this.user); 
     } 

     // No user - create new 
     this.user = new User(); 

     return Promise.resolve(this.user); 
    } 

    saveUser() { 
     this.getUser().then(() => { 
      window.localStorage.setItem('user', JSON.stringify(this.user)); 
     }); 
    } 

    updateUser (user) { 
     this.getUser().then(() => { 
      Object.assign(this.user, user); 

      this.saveUser(); 
     }); 
    } 

    login() { 
     this.updateUser({ 
      isLoggedIn: true 
     }); 

     return Promise.resolve(true); 
    } 
} 

定製element.js

import { inject } from 'aurelia-framework'; 

import { UserService } from 'user.service'; 

@inject (UserService) 
export class CustomElement { 
    constructor (userService) { 
     this.userService = userService; 
    } 

    attached() { 
     this.userService.getUser().then(user => { 
      this.user = user; 

      console.log('Fetched user:'); 
      console.dir(this.user); 

      console.log('Same?'); 
      console.dir(this.user === user); // this is true 
     }); 

     // At some point another custom element fires the UserService.login() method 
     // Here we check that our reference to the user also updates 

     setInterval(() => { 
      console.log('Is user logged in?'); 
      console.dir(this.user.isLoggedIn); // This is always false - even after UserService.login() has been called and UserService.user is updated (if I console.dir this.user inside UserService it is indeed updated) 

      // Grab a new version of UserService.user 
      this.userService.getUser().then(user => { 
       console.log('Fetched new user, is new user and our user same?'); 
       console.dir(this.user === user); // false :/ the new user fetched here actually has isLoggedIn === true but our this.user does not... 
      }); 
     }, 2000); 
    } 
} 

正如在評論中指出,在一個點其他自定義元素運行UserService.login()從而改變UserService.user.isLoggedIntrue(這體現在UserService如果我console.dirthis.user),但其他CustomElementthis.user更新。

順便說一句:Promise.resolve()UserService.getUser()的原因是,將來會有服務器調用。

Tbh對於這種類型的JS編程,來自jQuery世界的更多新東西,即使我基本上愛上了Aurelia這樣的東西,仍然讓我非常困惑,所以希望在這裏有一些見解: )

回答

2

看着你提供的代碼,我沒有看到什麼會導致你描述的行爲。

一個suggestion-使代碼更易於管理了一點,異步少......如果你的結構是這樣的:

user.js的

export class User { 
    loggedIn = false; 
    name = 'Anonymous'; 
} 

用戶商店。JS

@inject(User) 
export class UserStore { 
    constructor(user) { 
    this.user = user; 
    } 

    load() { 
    const serializedUser = localStorage.getItem('user'); 
    if (!info) { 
     return; 
    } 
    const storageUser = JSON.parse(serializedUser); 
    this.user.loggedIn = storageUser.loggedIn; 
    this.user.name = storageUser.name; 
    } 

    save() { 
    const serializedUser = JSON.stringify(this.user); 
    localStorage.setItem('user', serializedUser); 
    } 
} 

AUTH-service.js

@inject(User, UserStore) 
export class AuthService { 
    constructor(user, store) { 
    this.user = user; 
    this.store = store; 
    } 

    login(username, password) { 
    return fetch('https://api.megacorp.com/login', { method: 'POST' ... }) 
     .then(result => { 
     this.user.loggedIn = true; 
     this.user.name = result.name; 
     this.store.save(); 
     }); 
    } 
} 

定製element.js

@inject(User) 
export class CustomElement { 
    constructor(user) { 
    this.user = user; 
    } 

    ... 
} 

的好處是你的自定義元素永遠需要在採取DEP異步的東西。他們只是獲取應用程序的User實例,其實例可能會更改,但始終保持相同的實例。

+0

嗯,我不知道我遵循...你做的不同是,而不是'UserStore.user'是一個'新的用戶()'它實際上是用戶模型?這不妨礙我在別處使用用戶模型嗎?另外,你會建議有一個單獨的'AuthService'?我已經基本上完成了整個系統,而沒有太多關於如何構建這種結構的東西。如果你有一個關於JS的OOP認證/用戶處理的教程或文章的鏈接,我很樂意閱讀它。 – powerbuoy

+0

你可以結合UserStore和AuthStore,沒有硬性規則,做你最適合的方法。我試圖展示的主要內容是取決於用戶的東西不需要異步API。他們可以通過依賴它來訪問用戶實例(使用'@ inject')。對用戶執行操作(將其從匿名狀態移動到登錄狀態)可能是異步的(AuthService是異步的,但UserStore不是)。 –

+0

好的,我將不得不試驗一下這個,看看我是否理解了一切。但是,你的代碼的主要區別在於你將'UserService.user'設置爲實際的'User'類而不是'User'類的實例(使用'new User()')?這就是爲什麼當我稍後在我的自定義元素中注入相同的'User'類時,它們將會是相同的嗎? – powerbuoy

相關問題