问题
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