【问题标题】:Behaviour subject initial value null?行为主体初值null?
【发布时间】:2017-11-25 09:09:02
【问题描述】:
private customer: Subject<Object> = new BehaviorSubject<Object>(null);

setCustomer(id, accountClassCode) {
    this.customer.next({'id': id, 'accountClassCode': accountClassCode});
}

getCustomer() {
    return this.customer.asObservable();
}

我正在使用这部分代码,但我收到一个错误,找不到空的 id。有没有办法获取不为空的初始值?

【问题讨论】:

  • 你试过空对象吗?新的 BehaviorSubject({});
  • 有一个解决方案。如果不需要初始值,请勿使用 BehaviorSubject。
  • 我不需要初始值,但如果我不使用 BehaviorSubject,我的服务将无法正常工作
  • @windmaomao 因为如果您之后创建了任何新订阅,他们将永远无法获得该价值
  • @dotbert 在这种情况下并非如此 :-) 这里的目的不是触发订阅处理程序,除非有需要处理的值。

标签: angular typescript rxjs


【解决方案1】:

另一种方法是使用管道进行过滤,直到收到非空值。也可以使用 takeWhile 来完成。

.pipe(filter(val =&gt; !!val)).subscribe(x =&gt; {});

【讨论】:

    【解决方案2】:

    由于对象可以为空,更好的选择是像这样推断类型

     private customer = new BehaviorSubject<Customer|null>(null);
    

    【讨论】:

      【解决方案3】:

      我发现在很多情况下,我想要 ReplaySubject(1) 的简单性,但也想要 BehaviorSubjectvalue 属性,即它存储您最近的检索值而无需订阅。考虑到需要广播的初始值,使用BehaviorSubject 总是很烦人,这是我很少想要的条件。为此,我创建了自己的CurrentSubject

      import { ReplaySubject } from "rxjs";
      
      export class CurrentSubject<T> extends ReplaySubject<T> {
          value: T;
      
          set(value?: T) {
              this.value = value;
              this.next(value);
          }
      }
      

      我想覆盖next 方法,但由于某种原因我无法让它工作,所以我选择了一个名为set 的方法。我的覆盖尝试看起来像这样......

      export class CurrentSubject<T> extends ReplaySubject<T> {
          value: T;
      
          next(value?: T) {
              this.value = value;
              super.next(value);
          }
      }
      

      我不知道为什么覆盖不起作用。

      【讨论】:

      • 出了什么问题?这里需要在构造函数中调用 super() 吗?
      • 尝试覆盖下一个的问题?我不知道,我从来没有解决过这个问题,而是选择了我概述的 set 属性。如果您想尝试显式添加构造函数并调用 super() 只是为了看看这是否可行,请告诉我! :)
      • 当我尝试覆盖下一个时,我也遇到了同样的问题。通过调试发现,在没有覆盖的情况下,在扩展类上调用next时,nextInfiniteTimeWindow实际上是由ReplaySubject执行的,但是覆盖next并调用super.next时,却是来自@的next被调用的 987654337@ 类而不是 nextInfiniteTimeWindow。我没有费心去解决这个问题,所以我将ReplaySubject 类包装在我自己的类中并公开了相同的方法。
      • 同样的事情发生在我身上,我无法用最新版本的 TypeScript 和 RxJS 覆盖 next 方法。有什么想法吗?
      • 在这里解释了问题-stackoverflow.com/a/69696916/2405040
      【解决方案4】:

      尝试以这种方式构建您的服务:

      服务:

      @Injectable()
      export class MyService {
          customerUpdate$: Observable<any>;
      
          private customerUpdateSubject = new Subject<any>();
      
          constructor() {
              this.customerUpdate$ = this.customerUpdateSubject.asObservable();
          }
      
          updatedCustomer(dataAsParams) {
              this.customerUpdateSubject.next(dataAsParams);
          }
      }
      

      记得将MyService添加到提供者。

      你更新你的客户端(如果是这种情况),你做这样的事情:

      组件(触发的那个):

      constructor(private myService: MyService) {
              // I'll put this here, it could go anywhere in the component actually
              // We make things happen, Client has been updated
              // We store client's data in an object
              this.updatedClient = this.myObjectWithUpdatedClientData;  // Obj or whatever you want to pass as a parameter
              this.myService.updatedCustomer(this.updatedClient);
          }
      

      组件(订阅的那个):

      this.myService.customerUpdate$.subscribe((updatedClientData) => {
                  // Wow! I received the updated client's data
                  // Do stuff with this data!
              }
          );
      

      据我了解,您正试图将数据从一个组件传递到另一个组件。您获取客户的数据并通过您的应用程序将其发送到另一个组件,对吗?这就是我发布此解决方案的原因。

      如果您对其他类型的订阅感兴趣,请阅读以下内容:

      Angular 2 special Observables (Subject / Behaviour subject / ReplaySubject)

      【讨论】:

      • 嗯,我复制粘贴了确切的解决方案,但由于某种原因它对我不起作用,很奇怪。
      【解决方案5】:

      BehaviorSubject 的目的是提供初始值。它可以是null 或其他任何东西。如果无法提供有效的初始值(当用户 ID 未知时),则不应使用它。

      ReplaySubject(1) 提供类似的行为(在订阅时发出最后一个值),但在使用 next 设置之前没有初始值。

      应该是这样的

      private customer: Subject<Object> = new ReplaySubject<Object>(1);
      

      【讨论】:

      • 不指定默认为1,所以new ReplaySubject&lt;Foo&gt;()更好。顺便说一句,指定类型在运行时没有任何作用,但在编译时提供类型安全。
      • 首选ReplaySubject.create&lt;Object&gt;(1)
      • @Simon_Weaver 当前默认值(2019 年 11 月)是无穷大。设置 1 是必需的。 rxjs-dev.firebaseapp.com/api/index/class/ReplaySubject
      • @Mamkad 可能有基本的解构,map(([one, two]) =&gt; ({ one, two }))
      • @EstusFlask 感谢您的精彩帖子。你帮我分配。将我的代码中的示例附加到用户(测试工作) private _user$= new ReplaySubject(); this._user$.next(user) ;
      猜你喜欢
      • 2021-04-07
      • 1970-01-01
      • 2019-04-20
      • 2019-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-06
      • 1970-01-01
      相关资源
      最近更新 更多