首页 文章

角度4变量第一次不更新

提问于
浏览
2

这是我面临的问题 .

我在一个分配给指令的组件中有一个变量 . 我正在使用ngrx来发送和触发事件 . 所以问题是变量第一次没有更新 . 之后没有问题 .

我有一个谷歌 Map 和图标,点击任何图标,它使用id和 Map 边界调用服务器,然后与返回的数据一起调度一个动作 .

private getFromServer(id, bound_corners){
    let params = { bounds: bound_corners }
    return this.restangular.all('get-data/'+id)
            .customGET("", params)
            .map((d:any)=>{
                return d.plain();
            });
}

public onClick(icon){
    let bound_corners = this.getMapBounds();

    this.getFromServer(icon.id, bound_corners).subscribe((d)=>{

        this.store.dispatch(new action.detail(d, id));

    });
}

In the component class

let temp = store.select(fromRoot.getIconDetail);

temp.subscribe((d)=>{
    this.data = d;
})

在组件中,this.data第一次没有更新 . 如果我控制日志(this.data)然后它工作但它没有在HTML中更新 .

如果我从getFromServer订阅中取出调度操作,如下所示:

public onClick(icon){
    let bound_corners = this.getMapBounds();

    let temp_data = {name:"test","id":0};

    this.store.dispatch(new action.detail(temp_data, id));
}

然后它工作 .

目前我有一个使用ChangeDetectorRef的解决方案 .

constructor(private chRef: ChangeDetectorRef){

    let temp = store.select(fromRoot.getIconDetail);

    temp.subscribe((d)=>{
        this.data = d;
        this.chRef.detectChanges();
    });
}

我不确定这是否是正确的方法,但我无法弄清楚发生了什么或任何其他解决方案 .

任何帮助将不胜感激 . 谢谢

3 回答

  • 2

    也许不是将订阅分配给变量,而是直接执行它 .

    constructor(){
    
    store.select(fromRoot.getIconDetail)
        .subscribe(d => {
              this.data = d;
        })
    
    }
    

    值得注意的是,当您使用.subscribe时,您需要在组件被销毁时取消订阅,或者当重新访问和重新加载组件时,您将最终在Observable上累积多个订阅 .

    为了防止这种情况,并防止内存泄漏,您应该在销毁每个组件时取消订阅Observable .

    将这些导入添加到组件中

    import 'rxjs/add/operator/takeUntil';
    import { Subject } from 'rxjs/Subject';
    

    在你的类中添加它 - 我通常在构造函数上面执行此操作 .

    private ngUnsubscribe: Subject<any> = new Subject<any>()
    

    添加ngOnDestroy函数

    ngOnDestroy() {
        this.ngUnsubscribe.next();
        this.ngUnsubscribe.complete();
      }
    

    然后在你的.subscribe之前立即添加它(你应该在具有倍数的组件中的每个.subscribe之前使用这个确切的语法) .

    .takeUntil(this.ngUnsubscribe)
    

    所以在你的情况下,它看起来像这样 .

    constructor(){
    
    store.select(fromRoot.getIconDetail)
        .takeUntil(this.ngUnsubscribe)
        .subscribe(d => {
              this.data = d;
        })
    
    }
    

    所以会发生什么是订阅将保持活动状态,直到您离开组件为止,此时ngOnDestroy将彻底清除Observable中取消订阅的内容 .

  • 0

    这就是我最终做的 . 希望有人发布更好的解决方案 . 感谢Stephen对取消订阅的建议 .

    constructor(private ngZone: NgZone){
        store.select(fromRoot.getIconDetail)
        .takeUntil(ngUnsubscribe)
        .subscribe((d)=>{
            this.ngZone.run(() => {
                this.someFunction(d);
            });
        });
    }
    
  • 3

    在具有单向数据流范例的Angular中,所有用于存储数据的数据订阅都应该直接在带有异步管道的html中使用 .

    你没有't shown your html, but presume it',像 <div>{{data}}</div> .
    相反它应该是 <div>{{temp | async}}</div> .

    如果要引用可观察对象的属性,则需要将异步管道置于括号内: <div>{{ (temp | async).someProp }}</div> .

    此外,根据商店的初始状态,添加 safe navigation ('?')运算符通常很有用,以避免在预初始化阶段出现错误: <div>{{ (temp | async)?.someProp }}</div> . 参考:link

    这应该使您的模板对商店更改起反应,而无需调用更改检测(这是您使用ChangeDetectorRef灵魂和NgZone灵魂所做的事情) . 看看ngrx示例应用程序,例如find-book-page.ts . 看到命名约定,它是's useful to suffix an observable with ' $',所以temp $而不是temp .

    顺便说一下,我没有看到显式调用更改检测有什么问题 - 在包装第三方库时有时需要这样做 .

相关问题