In Rxjs is it an anti-pattern if you add a value to an array, and then immediately after emit that array as an observable?

风流意气都作罢 提交于 2019-12-11 10:58:17

问题


In my angular application, I want user to be able to upload few images and then I want to display their preview using subjects and observables.

My component.ts file has these properties:

uploadPicturesSubject$: Subject<any[]> = new Subject<any[]>();
  previewUrls$: Observable<any[]> = this.uploadPicturesSubject$.asObservable();
  previewUrls: any[] = [];

Then in my event handler for the (change) event (when user uploads photos) I have the following code:

...
const reader: FileReader = new FileReader();
      reader.readAsDataURL(uploadPicture.file);
      reader.onload = (event: any) => {        
        this.previewUrls.push(event.target.result)
        this.uploadPicturesSubject$.next(this.previewUrls);
      };

In my template I use the async pipe to subscribe the the previewUrls$ observable and everything works as expected. I wasn't sure if adding the src of the uploaded image with the line this.previewUrls.push(event.target.result) and then emitting the array this.uploadPicturesSubject$.next(this.previewUrls); was an anti-pattern or not because it felt like there was more code doing it this way, rather than simply in the html template doing an *ngFor loop on the this.previewUrls array as it achieves the same result.

Thanks for any insight.


回答1:


To me, mixing reactive patterns (subjects, observables) with other patterns where state is stored in local variables seems like an anti-pattern.

To prevent this, I'd take a different approach:

I'd start with just an uploadPicture subject (would be great to get some typing in to avoid 'any'). The idea here is only one picture ever goes into it at a time.

uploadPicture = new Subject<any>();

Then I'd set up another observable that hooks into this uploadPicture subject:

previewUrls$ = uploadPicture.pipe(
    scan((pictures, newPicture) => pictures.concat(newPicture), [])
)

What's great about scan is it emits every time a value comes through. To me (and a recent tweet by Ben Lesh confirmed this), it is one of the most powerful operators in RxJS.

So any time a new picture comes in, you just next on the uploadPicture subject:

this.uploadPicture.next(event.target.result)

and the whole array including the new picture will emit from previewUrls$.

From here, you should just be able to async pipe previewUrls$ and get the same result.



来源:https://stackoverflow.com/questions/56309242/in-rxjs-is-it-an-anti-pattern-if-you-add-a-value-to-an-array-and-then-immediate

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!