在角度服务中频繁使用BehaviorSubject是危险信号吗? [英] Is frequent use of BehaviorSubject in Angular services a red flag?

查看:21
本文介绍了在角度服务中频繁使用BehaviorSubject是危险信号吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用ANGLE编写应用程序,并且发现自己经常使用此模式:

@Injectable(...)
export class WidgetRegsitryService {
  private readonly _widgets: BehaviorSubject<Widget[]> = new BehaviorSubject([]);
  public get widgets() { return this._widgets.value; }
  public readonly widgets$ = this._widgets.asObservable();

  public add(widget: Widget) {
    const old = this._widgets.value.slice();
    old.push(widget);
    this._widgets.next(old);
  }
}

许多服务将有3-5个或更多这样的公共获得者和私人支持主体。它发生得如此之多,以至于代码感觉非常冗长和重复。那么:a)有没有干的方法,b)我是不是误用了观测数据?

推荐答案

我正在使用ANGLE编写应用程序,并且发现自己经常使用此模式:

您所显示的模式与状态存储非常相似,例如;ReduxNgRXNGXS。不同之处在于您已将存储区、选择器和减法器放入单个类中。

将所有内容放在一个位置有好处,但如果您每次启动新服务时都必须重写一个新存储区,那么这就解释了为什么您会说"发生的事情太多了,代码感觉非常冗长和重复"。

这没有什么错,Internet上有很多博客文章试图用尽可能少的代码行来编写Redux克隆。我的观点是,人们一直在做你一直在做的事情。

private readonly _widgets: BehaviorSubject<Widget[]> = new BehaviorSubject([]);

以上是状态管理器的存储。它是包含当前状态并发出对该状态的更改的可观察对象。

public get widgets() { return this._widgets.value; }

以上是状态管理器的快照。这允许您在不必订阅的情况下对存储执行特定计算,但就像使用快照的其他状态存储一样,可能会出现争用条件问题。您也不应该直接从模板访问它,因为它会触发"检查后表达式已更改"错误。

public readonly widgets$ = this._widgets.asObservable();

以上是存储的选择器。存储区通常会有许多选择器,这些选择器允许应用程序的不同部分侦听特定主题的存储区更改。

public add(widget: Widget) {
   const old = this._widgets.value.slice();
   old.push(widget);
   this._widgets.next(old);
   // above can be rewritten as
   this._widgets.next([...this.widgets, widget]);
}

状态存储库中没有上述内容。以上内容分为两个部分:操作还原器操作通常包含有效负载(在您的示例中是小部件),减少器执行修改存储的工作。

当我们使用操作和减法器时,它将存储应该如何更改的业务逻辑与读取当前状态、更新状态和保存下一个状态的问题解耦。虽然你的例子很简单。在必须订阅、修改和发出的大型应用程序中,当您只需切换布尔标志时,更改可能会成为开销样板代码。

许多服务将有3-5个或更多这样的公共获得者和私人支持主体。它发生得如此之多,以至于代码感觉非常冗长和重复。

您正在进入重新发明轮子的领域。

在我看来,您有两个可能的选择。发明您自己的状态存储框架,它会让您感觉更舒服,或者使用我上面列出的某个库中的现有状态存储。我们不能告诉您应该走哪条路,但我做过很多角度项目,我可以告诉您没有正确的答案。

真正让源代码感觉不那么冗长和重复的是非常固执己见的。使它不那么冗长的事情有一天可能会作为一个设计错误回来困扰您,重复的源代码是痛苦的,但有一天您会庆幸您可以修改一行代码,而不会影响源代码的其他部分。

a)是否有干法,并且

使源代码枯竭的唯一方法是将状态管理的实现与业务逻辑分离。这就是我们开始讨论是什么构成状态存储的好设计模式的地方。

  • 您使用选择器吗?
  • 您是否使用操作?
  • 您使用减速机吗?

您希望这些内容放在哪里(放在它们自己的文件中,还是放在服务的方法中?)您希望如何命名它们,是应该重新使用它们,还是应该为每个边缘案例创建新的名称?

很多问题实际上都是个人选择。

我可以使用NGXS作为示例重写您的示例,但这可能看起来枯燥,因为框架需要复杂才有用。我可以告诉您的是,当您需要做以前没有做过的事情时,阅读NGXS的文档会更容易,然后尝试自己发明它,并冒着出错的风险。这并不意味着NGXS总是正确的,但至少您可以抱怨这不是您的错:)

@State<Widget[]>({
    name: 'widgets',
    defaults: []
})
export class WidgetState {
    @Action(AddWidgetAction)
    public add(ctx: StateContext<Widget[]>, {payload}: AddWidgetAction) {
        ctx.setState([...ctx.getState(), payload]);
    }
}

@Component({...})
export class WidgetsComponent {
    @Select(WidgetState)
    public widgets$: Observable<Widget[]>;

    public constructor(private _store: Store) {};

    public clickAddWidget() {
        this._store.dispatch(new AddWidgetAction(new Widget()));
    }
}

b)我在这里是否误用了可观测数据?

绝对不能滥用观测数据。您已经很好地理解了为什么服务应该是无状态反应性。我认为您刚刚自己发现了州存储的价值,现在您正在寻找使其更容易使用的方法。

这篇关于在角度服务中频繁使用BehaviorSubject是危险信号吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆