最近组织组内程序员们向 Angular 迁移,有个编程风格的问题想咨询一下大家。
鉴于 Angular 大力推行 Rxjs 库的函数式思想比较有趣,同时又由于大家对这个范式的想法不同,写组件的时候浮现出很多不同的写法,例如下面这个小 Demo
一个简单组件有一个布尔值用来控制一个内容是否显示,两个按钮用来控制这个布尔值是真是假
//component.ts
... //跳过类内其他的定义
stat: bool = false;
onActiveButtonClicked():void {
this.stat = true;
}
onDeActiveButtonClicked():void {
this.stat = false
}
... //跳过类内其他的定义
//component.html
<button (click)="onActiveButtonClicked()">Active</button>
<button (click)="onDeActiveButtonClicked()">Deactive</button>
<p *ngIf="stat">Active</p>
以上代码是程序员 A 贡献的,这个程序员呢原来是做 iOS 客户端开发的,熟练掌握 MVC 设计模式,根据习惯写出了以上代码,完美运行(那是当然的)他坚持只使用 rxjs 处理数据,而不是这种一眼就能看出来的情况
还有一种写法如下,
//component.ts
...
dispatchAction: Subject<boolean> = new Subject<boolean>();
shouldActive :Observable<boolean> = this.dispatchAction.pipe(
startWith(false)
)
...
//component.html
<button (click)="dispatchAction.next(true)">Active</button>
<button (click)="dispatchAction.next(false)">Deactive</button>
<p *ngIf="shouldActive | async">Active</p>
这段代码是由我们刻苦学习的实习生贡献的,熟练运用 rxjs 给 Angular 赋能
就事论事的话,我们暂且不考虑复杂的业务会给“MVC 程序员”(当然了我们现在是 MVVM )带来多大的思想负担导致他变成“Massive View Controller 程序员”,也不考虑复杂的业务会让实习生写出
combinelatest(blablabal).pipe(bla(), merge(bkaba.pipe(nbikad)),switchmap(blablabal => forkjoin(blablalala)))
这种给 code review 带来无穷麻烦的代码,以上两种写法各位偏向于哪一种呢?
一个动态 DEMO 放在 stackblitz 上
https://stackblitz.com/edit/angular-kssmku?embed=1&file=src/app/app.component.html
在此先谢谢大家
朱朱
1
noe132 2020-03-06 18:00:04 +08:00
我的倾向是不要在模板里写 rxjs。模板的数据来源应该尽可能简单,这样后期维护会方便很多
其他地方怎么简单怎么写 |
2
Zhuzhuchenyan OP @noe132 其实我这里更多想问的是,对于这个 active 的状态,更倾向于用何种方式去管理。
第一种方式人类更能读懂,但是更新状态的代码散落在两个函数里 第二种方式用 rxjs 的话,更有一种数据在单向流动的感觉,状态的更新完全是由 Observer 的逻辑在托管 |
3
rrfeng 2020-03-06 18:12:04 +08:00 via Android
显然第一种啊。rxjs 用在该用的地方,第二种就是纯粹为了用 rxjs 而用......
楼上说的模板里不要写代码也是一种规范吧。 |
4
noe132 2020-03-06 18:17:26 +08:00
这并不冲突。
你只要把函数改成 handleSetState(active: boolean): unknown 就可以了 模板里写 handleSetState(true) |
5
Zhuzhuchenyan OP @noe132 的确这样似乎不错,handlestate 的逻辑就可以藏在 component 里了
|
6
Zhuzhuchenyan OP @rrfeng 个人能容忍的底线也就是调用.next 了,比这个更复杂的都会让他们去修改。
|
7
crs0910 2020-03-06 19:24:23 +08:00
shouldActive = new BehaviorSubject<boolean>(false);
不行吗? |
8
wunonglin 2020-03-06 19:38:20 +08:00
```ts
isShow: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false) setStatus(value: boolean): void{ this.isShow.next(value) } ``` ```html <button (click)="setStatus(true)">open</button> <button (click)="setStatus(false)">close</button> <div *ngIf="isShow | async"></div> ``` |
9
wunonglin 2020-03-06 19:39:02 +08:00
两行东西搞完的写那么复杂作甚?
|
10
wunonglin 2020-03-06 19:39:20 +08:00
不要为了用而用
|
11
nannanziyu 2020-03-06 19:59:15 +08:00 1
@wunonglin
... 哪儿用得了这么多行, 纯 html 就能实现 ``` <ng-container *ngIf="true; let isShow"> <button (click)="isShow=true">Active</button> <button (click)="isShow=false">Deactive</button> <p *ngIf="isShow">Active</p> </ng-container> ``` |
12
nannanziyu 2020-03-06 19:59:35 +08:00
|
13
Zhuzhuchenyan OP @crs0910 完全可以的,在写的时候因为是从一个比较复杂的东西上拿下来的,所以没有这么写
|
14
Zhuzhuchenyan OP @wunonglin 嗯,简单的东西肯定要保持简单,这里问的只是在复杂情况下的一种抽象而已
|
15
crs0910 2020-03-06 20:16:17 +08:00
@Zhuzhuchenyan #13 刚好看到隔壁在讨论这个 https://www.v2ex.com/t/650483
我觉得跟你的问题本质是相同的。 我觉得算上产品迭代,技术沉淀等因素,在某些时候某些场景看似“过度”的解决方案,长远来看收益是大过于成本的。 |
16
yuuko 2020-03-06 20:16:29 +08:00
如果只是简单的控制隐藏显示,肯定是第一种了,这种情况还用第二种的是为了用 rxjs 而用 rxjs。但是如果这个隐藏显示还要触发其他流程,比如数据获取之类的则可以用第二种。
|
17
Zhuzhuchenyan OP @yuuko 嗯的确,这个例子的确太简单了。现在基本也是只有复杂逻辑才交给 rxjs 去做。
|
18
Zhuzhuchenyan OP @crs0910 嗯我们现在对新东西也是摸着石头过河,整体的团队指导规范根据项目迭代以变化了好几版了。现在我们只有对“预估非常复杂的组件”才会使用较为复杂的结构,其他的东西我们宁愿写的越简单越好。
|
19
crysislinux 2020-03-06 23:47:15 +08:00 via Android
我们用了四年 angular 了,从 angular2 还是 beta 就在用。rxjs 这东西除非正好符合典型应用,否则还是别用。我们老大就喜欢瞎用,写的又臭又长,一旦 bug 简直无法。
|
20
crysislinux 2020-03-06 23:49:14 +08:00 via Android
而且 rxjs 这东西用多了,模板里到处 async,很难搞清楚到底哪个地方 trigger 了 change detection
|
21
Zhuzhuchenyan OP @crysislinux 好的受教了,看来还是需要辨识出 rxjs 的典型场景。
|
22
coloz 2020-03-07 21:11:04 +08:00
状态管理 BehaviorSubject
|