Cod*_*rer 4 observable rxjs typescript angular
我正在使用 Angular 编写一个应用程序,并发现自己经常使用这种模式:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
许多服务将有 3-5 个或更多这样的公共 getter 和私人支持主题组。它发生得太多了,以至于代码感觉非常冗长和重复。所以:a) 有没有一种干的方式来做到这一点,b) 我在这里滥用 Observables 吗?
我正在使用 Angular 编写一个应用程序,并发现自己经常使用这种模式:
您展示的模式与状态存储非常相似,例如;Redux、NgRX或NGXS。不同之处在于您已将存储、选择器和化简器放在一个类中。
把所有东西放在一个地方有好处,但是如果你每次启动新服务时都必须重写一个新商店,那么这就可以解释为什么你说“它发生的太多以至于代码感觉非常冗长和重复”。
这没有什么问题,网上也有很多博文试图用尽可能少的代码行写出一个 Redux 克隆。我的观点是人们一直在做你正在做的事情。
private readonly _widgets: BehaviorSubject<Widget[]> = new BehaviorSubject([]);
Run Code Online (Sandbox Code Playgroud)
上面是状态管理器的存储。它是一个 observable,包含当前状态并发出对该状态的更改。
public get widgets() { return this._widgets.value; }
Run Code Online (Sandbox Code Playgroud)
以上是状态管理器的快照。这允许您在无需订阅的情况下对存储进行特定计算,但就像使用快照的其他状态存储可能存在竞争条件问题一样。您也不应该直接从模板访问它,因为它会触发“检查后表达式已更改”错误。
public readonly widgets$ = this._widgets.asObservable();
Run Code Online (Sandbox Code Playgroud)
以上是商店的选择器。商店通常有许多选择器,允许应用程序的不同部分侦听特定主题的商店更改。
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]);
}
Run Code Online (Sandbox Code Playgroud)
我们在州立商店图书馆中没有上述内容。以上分为动作和减速器两部分。该操作通常包含有效负载(在您的情况下是一个小部件),并且减速器执行修改存储的工作。
当我们使用 action 和 reducer 时,它将 store 应该如何改变的业务逻辑与读取当前状态、更新状态和保存下一个状态的问题分离。虽然你的例子很简单。在必须订阅、修改和发出更改的大型应用程序中,当您想要做的只是切换布尔标志时,这些更改可能会成为开销样板代码。
许多服务将有 3-5 个或更多这样的公共 getter 和私人支持主题组。它发生得太多了,以至于代码感觉非常冗长和重复。
您正在进入重新发明轮子的领域。
在我看来,您有两种可能的选择。发明你自己的状态存储框架,让你感觉更舒服,或者使用我上面列出的库之一中的现有状态存储。我们无法告诉您该走哪条路,但我参与过许多 Angular 项目,我可以告诉您没有正确的答案。
真正让源代码感觉不那么冗长和重复的东西是高度自以为是的。非常的事情,使得它更简洁也许有一天回来困扰你作为一个设计错误,重复的源代码是痛苦的,但有一天你会感谢你可以修改一行代码,没有它影响其他领域的您源代码。
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()));
}
}
Run Code Online (Sandbox Code Playgroud)
b) 我在这里滥用了 Observables 吗?
绝对不会滥用可观察对象。您已经很好地理解了为什么服务应该是无状态和反应性的。我认为您只是自己发现了state store的价值,现在您正在寻找更容易使用它们的方法。