Angular 一个有关编程风格的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Zhuzhuchenyan
V2EX    前端开发

Angular 一个有关编程风格的问题

  •  
  •   Zhuzhuchenyan 2020-03-06 17:50:33 +08:00 2433 次点击
    这是一个创建于 2123 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近组织组内程序员们向 Angular 迁移,有个编程风格的问题想咨询一下大家。

    鉴于 Angular 大力推行 Rxjs 库的函数式思想比较有趣,同时又由于大家对这个范式的想法不同,写组件的时候浮现出很多不同的写法,例如下面这个小 Demo

    一个简单组件有一个布尔值用来控制一个内容是否显示,两个按钮用来控制这个布尔值是真是假

    //omponent.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

    在此先谢谢大家

    朱朱

    22 条回复    2020-03-07 21:11:04 +08:00
    noe132
        1
    noe132  
       2020-03-06 18:00:04 +08:00
    我的倾向是不要在模板里写 rxjs。模板的数据来源应该尽可能简单,这样后期维护会方便很多
    其他地方怎么简单怎么写
    Zhuzhuchenyan
        2
    Zhuzhuchenyan  
    OP
       2020-03-06 18:07:47 +08:00
    @noe132 其实我这里更多想问的是,对于这个 active 的状态,更倾向于用何种方式去管理。
    第一种方式人类更能读懂,但是更新状态的代码散落在两个函数里
    第二种方式用 rxjs 的话,更有一种数据在单向流动的感觉,状态的更新完全是由 Observer 的逻辑在托管
    rrfeng
        3
    rrfeng  
       2020-03-06 18:12:04 +08:00 via Android
    显然第一种啊。rxjs 用在该用的地方,第二种就是纯粹为了用 rxjs 而用......

    楼上说的模板里不要写代码也是一种规范吧。
    noe132
        4
    noe132  
       2020-03-06 18:17:26 +08:00
    这并不冲突。
    你只要把函数改成 handleSetState(active: boolean): unknown 就可以了
    模板里写 handleSetState(true)
    Zhuzhuchenyan
        5
    Zhuzhuchenyan  
    OP
       2020-03-06 18:20:25 +08:00
    @noe132 的确这样似乎不错,handlestate 的逻辑就可以藏在 component 里了
    Zhuzhuchenyan
        6
    Zhuzhuchenyan  
    OP
       2020-03-06 18:21:30 +08:00
    @rrfeng 个人能容忍的底线也就是调用.next 了,比这个更复杂的都会让他们去修改。
    crs0910
        7
    crs0910  
       2020-03-06 19:24:23 +08:00
    shouldActive = new BehaviorSubject<boolean>(false);
    不行吗?
    shakaraka
        8
    shakaraka  
    PRO
       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>
    ```
    shakaraka
        9
    shakaraka  
    PRO
       2020-03-06 19:39:02 +08:00
    两行东西搞完的写那么复杂作甚?
    shakaraka
        10
    shakaraka  
    PRO
       2020-03-06 19:39:20 +08:00
    不要为了用而用
    nannanziyu
        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>
    ```
    Zhuzhuchenyan
        13
    Zhuzhuchenyan  
    OP
       2020-03-06 20:03:15 +08:00
    @crs0910 完全可以的,在写的时候因为是从一个比较复杂的东西上拿下来的,所以没有这么写
    Zhuzhuchenyan
        14
    Zhuzhuchenyan  
    OP
       2020-03-06 20:04:20 +08:00
    @wunonglin 嗯,简单的东西肯定要保持简单,这里问的只是在复杂情况下的一种抽象而已
    crs0910
        15
    crs0910  
       2020-03-06 20:16:17 +08:00
    @Zhuzhuchenyan #13 刚好看到隔壁在讨论这个 t/650483
    我觉得跟你的问题本质是相同的。
    我觉得算上产品迭代,技术沉淀等因素,在某些时候某些场景看似“过度”的解决方案,长远来看收益是大过于成本的。
    yuuko
        16
    yuuko  
       2020-03-06 20:16:29 +08:00
    如果只是简单的控制隐藏显示,肯定是第一种了,这种情况还用第二种的是为了用 rxjs 而用 rxjs。但是如果这个隐藏显示还要触发其他流程,比如数据获取之类的则可以用第二种。
    Zhuzhuchenyan
        17
    Zhuzhuchenyan  
    OP
       2020-03-06 20:30:18 +08:00
    @yuuko 嗯的确,这个例子的确太简单了。现在基本也是只有复杂逻辑才交给 rxjs 去做。
    Zhuzhuchenyan
        18
    Zhuzhuchenyan  
    OP
       2020-03-06 20:40:44 +08:00
    @crs0910 嗯我们现在对新东西也是摸着石头过河,整体的团队指导规范根据项目迭代以变化了好几版了。现在我们只有对“预估非常复杂的组件”才会使用较为复杂的结构,其他的东西我们宁愿写的越简单越好。
    crysislinux
        19
    crysislinux  
       2020-03-06 23:47:15 +08:00 via Android
    我们用了四年 angular 了,从 angular2 还是 beta 就在用。rxjs 这东西除非正好符合典型应用,否则还是别用。我们老大就喜欢瞎用,写的又臭又长,一旦 bug 简直无法。
    crysislinux
        20
    crysislinux  
       2020-03-06 23:49:14 +08:00 via Android
    而且 rxjs 这东西用多了,模板里到处 async,很难搞清楚到底哪个地方 trigger 了 change detection
    Zhuzhuchenyan
        21
    Zhuzhuchenyan  
    OP
       2020-03-07 05:55:23 +08:00
    @crysislinux 好的受教了,看来还是需要辨识出 rxjs 的典型场景。
    coloz
        22
    coloz  
       2020-03-07 21:11:04 +08:00
    状态管理 BehaviorSubject
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1038 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 17:40 PVG 01:40 LAX 09:40 JFK 12:40
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86