Sky*_*ker 13 javascript rxjs typescript angular
我设置了一个service跟踪登录用户.该服务返回一个Observable,并subscribe通知所有组件(目前只有一个组件订阅它).
服务:
private subject = new Subject<any>();
sendMessage(message: boolean) {
this.subject.next( message );
}
getMessage(): Observable<any> {
return this.subject.asObservable();
}
Run Code Online (Sandbox Code Playgroud)
Root App组件:(此组件订阅了observable)
ngAfterViewInit(){
this.subscription = this._authService.getMessage().subscribe(message => { this.user = message; });
}
Run Code Online (Sandbox Code Playgroud)
欢迎组件:
ngOnInit() {
const checkStatus = this._authService.checkUserStatus();
this._authService.sendMessage(checkStatus);
}
Run Code Online (Sandbox Code Playgroud)
App Component Html :(这是发生错误的地方)
<div *ngIf="user"><div>
Run Code Online (Sandbox Code Playgroud)
我正在做的事情:
我希望每个组件(Root App Component除外)将用户登录状态发送到Root App Component,这样我就可以在Root App Component Html中操作UI.
问题:
初始化欢迎组件时出现以下错误.
Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'true'.
Run Code Online (Sandbox Code Playgroud)
请注意,此*ngIf="user"表达式发生此错误,该表达式位于Root App Components HTML文件中.
有人可以解释这个错误的原因以及我如何解决这个问题?
旁注:如果您认为有更好的方法来实现我想要做的事情,请告诉我.
更新1:
将以下内容constructor解决问题,但不想使用constructor为此目的所以它似乎不是一个好的解决方案.
欢迎组件:
constructor(private _authService: AuthenticationService) {
const checkStatus = this._authService.checkUserStatus();
this._authService.sendMessage(checkStatus);
}
Run Code Online (Sandbox Code Playgroud)
Root App组件:
constructor(private _authService: AuthenticationService){
this.subscription = this._authService.getMessage().subscribe(message => { this.usr = message; });
}
Run Code Online (Sandbox Code Playgroud)
更新2:
这是傻瓜.要查看错误,请检查浏览器控制台.当应用程序加载布尔值true时应显示但我在控制台中收到错误.
请注意,这个plunkr是我的主应用程序的一个非常基本的版本.由于应用程序有点大,我无法上传所有代码.但是plunkr完美地证明了这个错误.
bry*_*n60 17
这意味着变化检测周期本身似乎已经引起了变化,这可能是偶然的(即变化检测周期以某种方式引起它)或有意的.如果您故意在更改检测周期中更改某些内容,则应重新触发新一轮的更改检测,这在此处不会发生.此错误将在prod模式下被抑制,但意味着您的代码中存在问题并导致神秘问题.
在这种情况下,具体问题是您正在更改子项的更改检测周期中影响父项的内容,并且这不会重新触发父项的更改检测,即使异步触发器(如observable)通常也会这样.它不会重新触发父级循环的原因是因为这违反了单向数据流,并且可能会导致子项重新触发父级更改检测周期,然后重新触发子级,然后再次触发父级,依此类推,并导致应用中的无限变化检测循环.
听起来好像我说儿童无法向父组件发送消息,但情况并非如此,问题是儿童在更改检测周期内无法向父母发送消息(例如作为生命周期挂钩),它需要在外部发生,就像响应用户事件一样.
这里最好的解决方案是通过创建一个新组件来阻止违反单向数据流,该新组件不是导致更新的组件的父组件,因此无法创建无限更改检测循环.这在下面的plunkr中得到了证明.
添加了子项的新app.component:
<div class="col-sm-8 col-sm-offset-2">
<app-message></app-message>
<router-outlet></router-outlet>
</div>
Run Code Online (Sandbox Code Playgroud)
消息组件:
@Component({
moduleId: module.id,
selector: 'app-message',
templateUrl: 'message.component.html'
})
export class MessageComponent implements OnInit {
message$: Observable<any>;
constructor(private messageService: MessageService) {
}
ngOnInit(){
this.message$ = this.messageService.message$;
}
}
Run Code Online (Sandbox Code Playgroud)
模板:
<div *ngIf="message$ | async as message" class="alert alert-success">{{message}}</div>
Run Code Online (Sandbox Code Playgroud)
略微修改的消息服务(只是一个稍微清洁的结构):
@Injectable()
export class MessageService {
private subject = new Subject<any>();
message$: Observable<any> = this.subject.asObservable();
sendMessage(message: string) {
console.log('send message');
this.subject.next(message);
}
clearMessage() {
this.subject.next();
}
}
Run Code Online (Sandbox Code Playgroud)
这不仅仅是让更改检测正常工作,而且没有创建无限循环的风险.它还使您的代码更加模块化,并更好地隔离责任.
https://plnkr.co/edit/4Th7m0Liovfgd1Z3ECWh?p=preview
| 归档时间: |
|
| 查看次数: |
14499 次 |
| 最近记录: |