V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Zhuzhuchenyan
V2EX  ›  前端开发

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

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

    最近组织组内程序员们向 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

    在此先谢谢大家

    朱朱

    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);
    不行吗?
    wunonglin
        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>
    ```
    wunonglin
        9
    wunonglin  
       2020-03-06 19:39:02 +08:00
    两行东西搞完的写那么复杂作甚?
    wunonglin
        10
    wunonglin  
       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 刚好看到隔壁在讨论这个 https://www.v2ex.com/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   ·   实用小工具   ·   2870 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 14:10 · PVG 22:10 · LAX 06:10 · JFK 09:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.