代码之家  ›  专栏  ›  技术社区  ›  dagda1

使用RXJS观察角度4中阵列的变化

  •  1
  • dagda1  · 技术社区  · 6 年前

    我在组件中具有以下属性:

      get isUploading() {
        return this.files.length > 0 && this.files.some((f) => f.state === FileUpLoadState.uploading);
      }
    

    然后我有一个绑定到该属性的进度组件:

    <md-progress-bar *ngIf="this.isUploading" mode="indeterminate">loading...
    </md-progress-bar>
    

    我有一个上传功能,它循环访问一个文件对象数组,并直接改变对象数组:

     upload(){
        this.files.forEach(async (uploadedFile) => {
          uploadedFile.state = FileUpLoadState.uploading;
    
          try {
            uploadResponse = await this.blobStorageService.upload(uploadedFile.file, {
              maxSingleShotSize,
              progress: (progress) => file.progress = progress.
            });
    
            uploadedFile.state = FileUpLoadState.success;
    
            this.uploadActions.persistUpload({ ...uploadedFile, ...uploadResponse });
          } catch (err) {
            uploadedFile.error = err.message;
            uploadedFile.state = FileUpLoadState.error;
          }
        });
      }
    

    我来自“反应世界”,观察的是像这样的财产变化,而不是你做的事情。

    使用一个可以观察到的RXJS是一种更好的方法,或者在角度上使用这个常见的习惯用法是什么?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Reactgular    6 年前

    我将试着解释现在发生的事情以及为什么不建议这样做以及一种替代方法。

    get isUploading() {
       return this.files.length > 0 && this.files.some((f) => f.state === FileUpLoadState.uploading);
    }
    

    以上是一个 状态 值可变的属性 异步地 upload() . Angular需要呈现组件的视图,以反映HTML中的任何更改。这都是通过变更检测自动完成的,您看到这些变更的原因是Angular使用区域来检测触发变更检测的异步操作。

    https://www.joshmorony.com/understanding-zones-and-change-detection-in-ionic-2-angular-2/

    你的例子是有效的,因为你在一个角度区域内创造了承诺。当您在一个区域内并创建一个异步侦听器时,Angular将模拟修补该操作,以便在异步操作完成时进行角度更改检测。

    await this.blobStorageService.upload(...)
    

    所以上面的代码行是在一个区域内执行的,当异步完成时,angular将遍历所有组件视图,以查看是否有任何更改。然后它将呈现任何脏的组件。

    我来自“反应世界”,观察的是像这样的财产变化,而不是你做的事情。

    你肯定不会做出反应,我也不能说我喜欢这个角度。

    开箱即用的角度不需要了解视图、区域和更改检测的工作原理。您可以这样做并快速创建一个可工作的应用程序,但它不能 规模 更大的应用程序。当您从组件中添加越来越多的视图时,更改检测会减慢并开始延迟。

    我们称之为 技术债务 因为如果应用程序的大小增加,那么您必须返回并重构要使用的内容 OnPush 变更检测。在你被 燃烧 通过这个角度的特征,你将永远使用 OnPress 从那以后。

    https://netbasal.com/a-comprehensive-guide-to-angular-onpush-change-detection-strategy-5bac493074a4

    作为一个反应开发者。你已经 斑点的 这很早,只是 感觉 错了,但你不明白为什么,我认为这真的说明了为什么反应变得如此流行。它从一开始就不允许问题存在,从而解决了角度上的一个重要问题。

    我只想知道这是角度开发者做这种事情的方式还是他们使用RXJ

    所以建议的方法是 OnPress 变更通知。一旦组件配置为使用 OnPress 然后在异步操作完成后,它的视图将不会被更新。Angular不会检测到更改,因为没有任何输入绑定发生更改。

    现在我们可以更好地回答你的问题了。当异步操作更改时,如何更新视图?

    将视图标记为“脏”

    可以将changeDetectRef类注入组件,然后将视图标记为脏视图。

    https://angular.io/api/core/ChangeDetectorRef#markforcheck

    当反应式编程需要重构源代码,或者根本不能使用反应式编程时,这是迄今为止最简单的解决方案。

        this.uploadActions.persistUpload({ ...uploadedFile, ...uploadResponse });
        this.changeDetectorRef.markforcheck();
    

    您只需在代码中添加一行,这将告诉Angular组件是脏的。

    我不会说这一方法是最佳实践,但这是你将如何使它与 OnPress 这才是最重要的。这个组件现在只需要在实际更改时进行更新,而Angular不需要一直检测更改。

    异步反应式编程

    反应式编程允许您使用 async 管子。

    https://angular.io/api/common/AsyncPipe

    其优点是管道句柄将视图标记为脏视图。因此,您可以创建一个使用 OnPress 响应异步操作而不必手动调用 markforcheck() 总是。

    您的模板将变成:

    <md-progress-bar *ngIf="isUploading | async" mode="indeterminate">loading...
    

    然后,该属性将是一个可观测的,发出真/假值。有很多方法可以转换您的 上传() 函数来发出值,但我不想尝试为您重写它。我想这不是真正的问题所在。

    推荐文章