2016-08-03 57 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