对对象的引用以某种方式丢失
Reference to Object is lost somehow
我正在使用 Aurelia 框架构建一个相当高级的应用程序,该框架使用模型、服务和自定义元素。
我有一个包含用户名、电子邮件等的用户模型以及一个 bool isLoggedIn。
我有一个将用户存储在 localStorage 中的用户服务,允许您更新用户数据等等。
我终于有了一些自定义元素,它们使用用户服务获取当前用户并根据用户是否登录显示 UI。
我面临的问题是,在我使用用户服务获取用户,然后从我的一个自定义元素(存储在用户服务中)更新用户模型后,另一个自定义元素引用了上述内容用户模型不会更新。
我试图在 JSFiddle 中复制这个问题(在普通 JS 中——我在 ES6 中写这个)但是没有这样做,在 fiddle 中一切正常。
有很多代码,但我想听听您的意见,我可能做错了什么才会发生这种情况?
这是我的要点:
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.isLoggedIn
更改为 true
(这反映在 UserService
中,如果我 console.dir
它 this.user
) 但另一个 CustomElement
的 this.user
不 更新。
顺便说一句:UserService.getUser()
中的Promise.resolve()
的原因是将来会有服务器调用。
老实说,我对 JS 中的这种类型的编程很陌生,更多来自 jQuery 世界,尽管我基本上爱上了像这样的 Aurelia 东西,但我仍然很困惑所以希望在这里获得一些见解:)
查看您提供的代码,我看不出什么会导致您所描述的行为。
一个建议 - 让您的代码更易于管理,减少异步...如果您将其结构化如下:
user.js
export class User {
loggedIn = false;
name = 'Anonymous';
}
用户-store.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;
}
...
}
好处是您的自定义元素永远不需要依赖异步的东西。他们只是获取应用程序的 User 实例,其属性可能会更改但将始终保持相同的实例。
我正在使用 Aurelia 框架构建一个相当高级的应用程序,该框架使用模型、服务和自定义元素。
我有一个包含用户名、电子邮件等的用户模型以及一个 bool isLoggedIn。
我有一个将用户存储在 localStorage 中的用户服务,允许您更新用户数据等等。
我终于有了一些自定义元素,它们使用用户服务获取当前用户并根据用户是否登录显示 UI。
我面临的问题是,在我使用用户服务获取用户,然后从我的一个自定义元素(存储在用户服务中)更新用户模型后,另一个自定义元素引用了上述内容用户模型不会更新。
我试图在 JSFiddle 中复制这个问题(在普通 JS 中——我在 ES6 中写这个)但是没有这样做,在 fiddle 中一切正常。
有很多代码,但我想听听您的意见,我可能做错了什么才会发生这种情况?
这是我的要点:
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.isLoggedIn
更改为 true
(这反映在 UserService
中,如果我 console.dir
它 this.user
) 但另一个 CustomElement
的 this.user
不 更新。
顺便说一句:UserService.getUser()
中的Promise.resolve()
的原因是将来会有服务器调用。
老实说,我对 JS 中的这种类型的编程很陌生,更多来自 jQuery 世界,尽管我基本上爱上了像这样的 Aurelia 东西,但我仍然很困惑所以希望在这里获得一些见解:)
查看您提供的代码,我看不出什么会导致您所描述的行为。
一个建议 - 让您的代码更易于管理,减少异步...如果您将其结构化如下:
user.js
export class User {
loggedIn = false;
name = 'Anonymous';
}
用户-store.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;
}
...
}
好处是您的自定义元素永远不需要依赖异步的东西。他们只是获取应用程序的 User 实例,其属性可能会更改但将始终保持相同的实例。