2

这是我面临的问题。

我在分配给指令的组件中有一个变量。我正在使用 ngrx 来调度和订阅事件。所以问题是变量第一次没有更新。之后就没有问题了。

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

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));

    });
}

在组件类中

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

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

在组件中 this.data 不会第一次更新。如果我控制台 log(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();
    });
}

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

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

4

3 回答 3

3

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

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 取消订阅。

于 2017-08-09T05:19:58.777 回答
2

这就是我最终所做的。希望有人发布更好的解决方案。感谢斯蒂芬的退订建议。

constructor(private ngZone: NgZone){
    store.select(fromRoot.getIconDetail)
    .takeUntil(ngUnsubscribe)
    .subscribe((d)=>{
        this.ngZone.run(() => {
            this.someFunction(d);
        });
    });
}
于 2017-08-09T08:04:55.263 回答
0

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

您还没有显示您的 html,但假设它类似于<div>{{data}}</div>.
相反,它应该是<div>{{temp | async}}</div>.

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

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

这应该使您的模板对存储更改做出反应,而无需调用更改检测(这是您使用 ChangeDetectorRef 灵魂和 NgZone 灵魂所做的)。查看 ngrx 示例应用程序,例如find-book-page.ts。请参阅命名约定,用 '$' 作为 observable 后缀很有用,所以用 temp$ 代替 temp。

顺便说一句,我认为显式调用更改检测没有任何问题 - 在包装 3rd 方库时有时需要这样做。

于 2017-08-10T00:38:27.850 回答