布莱恩F爱
向一位来自Portlandyobet英雄联盟的谷歌开发专家学习Angular、Web技术和Node.js。
广告 ·ultimatecourses.com
用终极课程学习Angular的正确方法

RxJS反模式

学习在Angular应用中不要用RxJS做什么。yobet外围

依赖的行为

这对我来说太重要了。我需要等到有了A才可以请求B。你可能会说,对B的请求取决于A的响应。

下面是反模式:

公共课程:可观测的<数组<课程>>;ngOnInit(){商店选择(getUser())takeWhile(()= >活着)第一个()订阅(用户= >{商店调度(LoadCoursesForUserAction({用户:用户}));课程=商店选择(getCourses);});}

让我解释一下我想要实现的目标:

  • 首先,我有一个公共财产课程这是一个可观察数组课程对象。
  • 我使用takeWhile ()在组件处于活动状态时完成订阅。我设置的值活着在…中造假ngOnDestroy ()生命周期方法。
  • 然后使用第()方法在发出第一个值后完成订阅。我只对获得经过身份验证的单个用户感兴趣。
  • 然后,使用。订阅可观察对象订阅()方法。我的观察者是使用一个胖箭头函数定义的用户论点。
  • 在观察者函数I内调度()为用户加载课程的新操作,命名恰当LoadCoursesForUserAction,提供了用户对象。
  • 最后,我将课程属性设置为存储中使用的课程数组getCourses ()选择器函数。

它的工作原理。

我知道我们都听过这句话,如果我们对自己诚实的话,很可能我们也说过同样的话。

同时,它的工作原理。有一种更好、更简洁的方法来处理依赖的动作。

让我们来看看,我认为更好的方法是:

公共课程:可观测的<数组<课程>>;ngOnInit(){课程=商店选择(getUser())(用户= >商店调度(LoadCoursesForUserAction({用户:用户})))switchMap(()= >商店选择(getCourses));}

让我们回顾一下更新代码:

  • 首先,注意我设置的值课程属性的结果switchMap ()操作符。
  • 我使用了做()操作符转换地执行操作(或副作用),在本例中为调度()LoadCoursesForUserAction行动。的做()操作员会收到用户对象创建的可观察对象发出的select ()方法,指定getUser ()选择器函数。
  • 最后,使用switchMap ()操作符,内部可观察对象(获取用户)完成,返回数组的可观察对象课程对象。

有什么好处?

  1. 我们不需要处理订阅和取消订阅。
  2. 它更简洁。
  3. 我们利用所提供的RxJs操作符。

如果我们有多个依赖项,比如:

  • C取决于B
  • B取决于A

下面是反模式的一个例子:

公共管理员=;公共集团:可观测的<集团>;公共用户:可观测的<数组<用户>>;ngOnInit(){常量PARAMS_ID=“id”;//获取id路由参数activatedRoute参数个数takeWhile(()= >活着)订阅(参数个数= >{//获取id参数常量id=参数个数(PARAMS_ID];//集合商店调度(LoadGroupAction({id:id}集团=商店选择(getGroup);集团takeWhile(()= >活着)过滤器(集团= >!!集团)第一个()订阅(集团= >{//以组加载用户商店调度(LoadUsersInGroupAction({集团:集团}));用户=商店选择(getUsersInGroup);/ /设置管理员商店选择(getAuthenticatedUser)takeWhile(()= >活着)第一个()订阅(用户= >{管理员=(集团安全管理员indexOf(用户_idtoString())>-1);});});})}

在这个例子中,依赖项是:

  • 我需要用户和组来确定用户是否是一个组的管理员。
  • 我需要组检索组中的用户。
  • 我需要route参数根据id值获取组。

这里的一些问题是:

  • 有很多嵌套订阅。
  • 这有点复杂,很难读懂。
  • 我用的是deprecated参数个数当我应该使用paramMap可观测的ActivatedRoute

这里有一个更好的方法来解决这个问题:

公共管理员=;公共集团:可观测的<集团>;公共用户:可观测的<数组&ltUser>>;ngOnInit(){集团=activatedRouteparamMaptakeWhile(()= >活着)(参数个数= >商店调度(LoadGroupAction({id:参数个数得到(PARAMS_ID)})))switchMap(()= >商店选择(getGroup));用户=集团(集团= >商店调度(LoadUsersInGroupAction({集团:集团})))switchMap(()= >商店选择(getUsersInGroup));管理员=集团switchMap(集团= >商店选择(getAuthenticatedUser)switchMap(用户= >可观测的(集团安全管理员indexOf(用户_idtoString())>-1)));}

以下是我更喜欢这个的几个原因:

  1. 它更短更简洁。
  2. 我可以将逻辑代码块组合在一起,使其更具可读性。
  3. 没有大量缩进的嵌套订阅。
  4. 我使用推荐的paramMap可观察到的。

避免重复请求

AsyncPipe可能是Angular中最酷的东西之一。我还记得2016年坐在ng-conf观看了一个关于Angular(当时叫做Angular 2)的演示,在演示异步管道时,台下响起了雷鸣般的掌声。对于我们这些已经用JavaScript做异步编码一段时间的人来说,它就像圣杯一样。这是纯粹的魔法。

但是,随着我变得越来越有棱角,我开始注意到一些奇怪的事情。如果我在组件的TypeScript文件中定义了一个可观察对象,然后使用async管道使用具有输入绑定的多个子组件,我注意到对于同一个端点有多个网络请求。

让我用代码来解释。这是我的组件:

公共课程:可观测的&l;课程>;ngOnInit(){常量PARAMS_COURSE_ID=“courseId”;/ /设置课程课程=activatedRouteparamMaptakeWhile(()= >活着)(参数个数= >商店调度(LoadCourseAction({id:参数个数得到(PARAMS_COURSE_ID)})))switchMap(()= >商店选择(getCourse))}

这是我的HTML模板:

<ama-module-menu>[course]="course | asyncama-module-menu><ama-module-content>"course | async >ama-module-content>

有几点需要注意:

  • 首先,在我的组件中ngOnInit ()生命周期钩子是我设置的公共值课程一个可观察对象的属性。这个值恰好来自一个使用选择器的NgRx存储,getCourse (),使用switchMap ()操作符。
  • 在我的模板中我有一个< ama-module-menu >元素的输入绑定课程,它使用异步管道。(顺便说一句,“ama”是“a million-dollar app”的首字母缩写。)
  • 在我的模板中,我也有< ama-module-content >元素的输入绑定课程,它也使用异步管道。

问题:对网络流量的快速回顾表明,异步管道将创建多个订阅,从而导致对同一资源的多个HTTP选项请求。有趣的是,Angular中的HttpClient模块似乎会取消多个GET请求,然后发出一个GET请求。

多个选项请求相同的端点

解决方案,使用分享()接线员:

share():在多个订阅者之间共享源。

分享()操作符非常容易使用,并且允许我们在模板中使用多个异步管道绑定时避免重复的HTTP请求。

只需调用分享()操作时,设置我们的观察:

常量PARAMS_COURSE_ID=“courseId”;/ /设置课程课程=activatedRouteparamMaptakeWhile(()= >活着)(参数个数= >商店调度(LoadCourseAction({id:参数个数得到(PARAMS_COURSE_ID)})))switchMap(()= >商店选择(getCourse))分享()}

注意,前面的组件代码和上面的这段代码之间只有一个区别:我们添加了分享()操作符。

结果在我们的视图模板中的多个异步管道订阅的单个HTTP GET请求。

单个选项请求相同的端点

谢谢你RxJs !

使用* ngIf

更新:2017-11-26

正如金伯利在下面的评论中指出的,您还可以使用* ngIf结果绑定以避免重复请求:

             
              (课程)= " c " >< ama-module-content >(课程)= " c >' ' '这样就避免了使用' .share() '操作符进行RxJs的多播。谢谢Kimberly分享这个解决方案!# #更多?这只是我观察到的两个反模式(哈哈)。请分享您所学到的任何其他反模式!

布莱恩F爱

嗨,我是布莱恩。我对TypeScript, Angular和Node.js感兴趣。我和我最好的朋友邦妮结婚了,我住在波特兰,我经常滑雪。