How can I give an RxJS observable pipe access to the original observable's emission AND the pipe's previous emission?
up vote
1
down vote
favorite
I have an RxJS Observable that emits a series of changes to an underlying data structure—specifically, snapshotChanges() from an AngularFirestoreCollection.
- I'm currently mapping this to an array of plain JavaScript objects for consumption by my app.
- This array is not protected in any way, and consuming code could accidentally modify this structure.
- The entire array is rebuilt whenever the underlying data source emits, even if only one (or sometimes no) item in the array has actually changed.
- Because of this, all references change each time, making change detection harder than it needs to be—and really slowing down my app.
What I want to do instead is use Immer to maintain an immutable structure, such that unchanged data is structurally shared with the “new” array.
What I can't work out is how to pipe()
off the snapshotChanges()
observable such that the pipe gets access to the previously emitted immutable data (or a first-time default) in addition to the latest snapshotChanges()
output.
In code, what I basically already have is this:
const docToObject = (doc) => /* change document to fresh plain object every time */ ;
const mappedData$ = snapshotChanges().pipe(
map(changes => changes.map(change => docToObject(change.payload.doc)),
tap(array => console.log('mutable array:', array)),
);
and I'm essentially looking for something like this, where I don't know what XXX(...)
should be:
const newImmutableObject = (changes, old) =>
// new immutable structure from old one + changes, structurally sharing as much as
// possible
;
const mappedData$ = snapshotChanges().pipe(
// ==================================================================================
XXX(...), // missing ingredient to combine snapshotChanges and previously emitted
// value, or default to
// ==================================================================================
map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);
I feel like the expand
operator is close to what I need, but it seems to only pass the previously emitted value in on subsequent runs, whereas I also need the newly emitted snapshotChanges
.
Given an RxJS Observable pipe, how can I operate on this Observable's emissions while also having access to the pipe's previous emission?
angular rxjs angularfire2 rxjs-pipeable-operators immer.js
add a comment |
up vote
1
down vote
favorite
I have an RxJS Observable that emits a series of changes to an underlying data structure—specifically, snapshotChanges() from an AngularFirestoreCollection.
- I'm currently mapping this to an array of plain JavaScript objects for consumption by my app.
- This array is not protected in any way, and consuming code could accidentally modify this structure.
- The entire array is rebuilt whenever the underlying data source emits, even if only one (or sometimes no) item in the array has actually changed.
- Because of this, all references change each time, making change detection harder than it needs to be—and really slowing down my app.
What I want to do instead is use Immer to maintain an immutable structure, such that unchanged data is structurally shared with the “new” array.
What I can't work out is how to pipe()
off the snapshotChanges()
observable such that the pipe gets access to the previously emitted immutable data (or a first-time default) in addition to the latest snapshotChanges()
output.
In code, what I basically already have is this:
const docToObject = (doc) => /* change document to fresh plain object every time */ ;
const mappedData$ = snapshotChanges().pipe(
map(changes => changes.map(change => docToObject(change.payload.doc)),
tap(array => console.log('mutable array:', array)),
);
and I'm essentially looking for something like this, where I don't know what XXX(...)
should be:
const newImmutableObject = (changes, old) =>
// new immutable structure from old one + changes, structurally sharing as much as
// possible
;
const mappedData$ = snapshotChanges().pipe(
// ==================================================================================
XXX(...), // missing ingredient to combine snapshotChanges and previously emitted
// value, or default to
// ==================================================================================
map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);
I feel like the expand
operator is close to what I need, but it seems to only pass the previously emitted value in on subsequent runs, whereas I also need the newly emitted snapshotChanges
.
Given an RxJS Observable pipe, how can I operate on this Observable's emissions while also having access to the pipe's previous emission?
angular rxjs angularfire2 rxjs-pipeable-operators immer.js
3
scan
seems to be what you are looking for:snapshotChanges().pipe(scan((prev, changes) => newImmutableObject(changes, prev), ))
– cartant
Nov 10 at 4:47
Thank you—this is exactly what I was looking for (I was so close!). The learn-rxjs page forscan
even says “You can create Redux-like state management with scan!” Example 2: Accumulating an object shows almost precisely what I'm trying to achieve.
– Alex Peters
Nov 10 at 14:11
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I have an RxJS Observable that emits a series of changes to an underlying data structure—specifically, snapshotChanges() from an AngularFirestoreCollection.
- I'm currently mapping this to an array of plain JavaScript objects for consumption by my app.
- This array is not protected in any way, and consuming code could accidentally modify this structure.
- The entire array is rebuilt whenever the underlying data source emits, even if only one (or sometimes no) item in the array has actually changed.
- Because of this, all references change each time, making change detection harder than it needs to be—and really slowing down my app.
What I want to do instead is use Immer to maintain an immutable structure, such that unchanged data is structurally shared with the “new” array.
What I can't work out is how to pipe()
off the snapshotChanges()
observable such that the pipe gets access to the previously emitted immutable data (or a first-time default) in addition to the latest snapshotChanges()
output.
In code, what I basically already have is this:
const docToObject = (doc) => /* change document to fresh plain object every time */ ;
const mappedData$ = snapshotChanges().pipe(
map(changes => changes.map(change => docToObject(change.payload.doc)),
tap(array => console.log('mutable array:', array)),
);
and I'm essentially looking for something like this, where I don't know what XXX(...)
should be:
const newImmutableObject = (changes, old) =>
// new immutable structure from old one + changes, structurally sharing as much as
// possible
;
const mappedData$ = snapshotChanges().pipe(
// ==================================================================================
XXX(...), // missing ingredient to combine snapshotChanges and previously emitted
// value, or default to
// ==================================================================================
map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);
I feel like the expand
operator is close to what I need, but it seems to only pass the previously emitted value in on subsequent runs, whereas I also need the newly emitted snapshotChanges
.
Given an RxJS Observable pipe, how can I operate on this Observable's emissions while also having access to the pipe's previous emission?
angular rxjs angularfire2 rxjs-pipeable-operators immer.js
I have an RxJS Observable that emits a series of changes to an underlying data structure—specifically, snapshotChanges() from an AngularFirestoreCollection.
- I'm currently mapping this to an array of plain JavaScript objects for consumption by my app.
- This array is not protected in any way, and consuming code could accidentally modify this structure.
- The entire array is rebuilt whenever the underlying data source emits, even if only one (or sometimes no) item in the array has actually changed.
- Because of this, all references change each time, making change detection harder than it needs to be—and really slowing down my app.
What I want to do instead is use Immer to maintain an immutable structure, such that unchanged data is structurally shared with the “new” array.
What I can't work out is how to pipe()
off the snapshotChanges()
observable such that the pipe gets access to the previously emitted immutable data (or a first-time default) in addition to the latest snapshotChanges()
output.
In code, what I basically already have is this:
const docToObject = (doc) => /* change document to fresh plain object every time */ ;
const mappedData$ = snapshotChanges().pipe(
map(changes => changes.map(change => docToObject(change.payload.doc)),
tap(array => console.log('mutable array:', array)),
);
and I'm essentially looking for something like this, where I don't know what XXX(...)
should be:
const newImmutableObject = (changes, old) =>
// new immutable structure from old one + changes, structurally sharing as much as
// possible
;
const mappedData$ = snapshotChanges().pipe(
// ==================================================================================
XXX(...), // missing ingredient to combine snapshotChanges and previously emitted
// value, or default to
// ==================================================================================
map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);
I feel like the expand
operator is close to what I need, but it seems to only pass the previously emitted value in on subsequent runs, whereas I also need the newly emitted snapshotChanges
.
Given an RxJS Observable pipe, how can I operate on this Observable's emissions while also having access to the pipe's previous emission?
angular rxjs angularfire2 rxjs-pipeable-operators immer.js
angular rxjs angularfire2 rxjs-pipeable-operators immer.js
asked Nov 10 at 2:58
Alex Peters
807515
807515
3
scan
seems to be what you are looking for:snapshotChanges().pipe(scan((prev, changes) => newImmutableObject(changes, prev), ))
– cartant
Nov 10 at 4:47
Thank you—this is exactly what I was looking for (I was so close!). The learn-rxjs page forscan
even says “You can create Redux-like state management with scan!” Example 2: Accumulating an object shows almost precisely what I'm trying to achieve.
– Alex Peters
Nov 10 at 14:11
add a comment |
3
scan
seems to be what you are looking for:snapshotChanges().pipe(scan((prev, changes) => newImmutableObject(changes, prev), ))
– cartant
Nov 10 at 4:47
Thank you—this is exactly what I was looking for (I was so close!). The learn-rxjs page forscan
even says “You can create Redux-like state management with scan!” Example 2: Accumulating an object shows almost precisely what I'm trying to achieve.
– Alex Peters
Nov 10 at 14:11
3
3
scan
seems to be what you are looking for: snapshotChanges().pipe(scan((prev, changes) => newImmutableObject(changes, prev), ))
– cartant
Nov 10 at 4:47
scan
seems to be what you are looking for: snapshotChanges().pipe(scan((prev, changes) => newImmutableObject(changes, prev), ))
– cartant
Nov 10 at 4:47
Thank you—this is exactly what I was looking for (I was so close!). The learn-rxjs page for
scan
even says “You can create Redux-like state management with scan!” Example 2: Accumulating an object shows almost precisely what I'm trying to achieve.– Alex Peters
Nov 10 at 14:11
Thank you—this is exactly what I was looking for (I was so close!). The learn-rxjs page for
scan
even says “You can create Redux-like state management with scan!” Example 2: Accumulating an object shows almost precisely what I'm trying to achieve.– Alex Peters
Nov 10 at 14:11
add a comment |
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
As per your requirement I would suggest to use scan
operator which can track all previous state and new state.
const newImmutableObject = (changes, old) =>
// new immutable structure from old one + changes, structurally sharing as much as
// possible
;
const mappedData$ = snapshotChanges().pipe(
scan((acc, current) => [...acc, current], ), //<-- scan is used here
map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);
Thank you. In fact, with thescan
operator I don't actually need the subsequentmap
operator after all.
– Alex Peters
Nov 10 at 14:13
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
As per your requirement I would suggest to use scan
operator which can track all previous state and new state.
const newImmutableObject = (changes, old) =>
// new immutable structure from old one + changes, structurally sharing as much as
// possible
;
const mappedData$ = snapshotChanges().pipe(
scan((acc, current) => [...acc, current], ), //<-- scan is used here
map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);
Thank you. In fact, with thescan
operator I don't actually need the subsequentmap
operator after all.
– Alex Peters
Nov 10 at 14:13
add a comment |
up vote
1
down vote
accepted
As per your requirement I would suggest to use scan
operator which can track all previous state and new state.
const newImmutableObject = (changes, old) =>
// new immutable structure from old one + changes, structurally sharing as much as
// possible
;
const mappedData$ = snapshotChanges().pipe(
scan((acc, current) => [...acc, current], ), //<-- scan is used here
map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);
Thank you. In fact, with thescan
operator I don't actually need the subsequentmap
operator after all.
– Alex Peters
Nov 10 at 14:13
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
As per your requirement I would suggest to use scan
operator which can track all previous state and new state.
const newImmutableObject = (changes, old) =>
// new immutable structure from old one + changes, structurally sharing as much as
// possible
;
const mappedData$ = snapshotChanges().pipe(
scan((acc, current) => [...acc, current], ), //<-- scan is used here
map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);
As per your requirement I would suggest to use scan
operator which can track all previous state and new state.
const newImmutableObject = (changes, old) =>
// new immutable structure from old one + changes, structurally sharing as much as
// possible
;
const mappedData$ = snapshotChanges().pipe(
scan((acc, current) => [...acc, current], ), //<-- scan is used here
map(([snapshotChanges, prevImmutableOutput]) => newImmutableOutput(...)),
tap(array => console.log('IMMUTABLE ARRAY with shared structure:', array)),
);
answered Nov 10 at 9:41
Sunil Singh
5,6161625
5,6161625
Thank you. In fact, with thescan
operator I don't actually need the subsequentmap
operator after all.
– Alex Peters
Nov 10 at 14:13
add a comment |
Thank you. In fact, with thescan
operator I don't actually need the subsequentmap
operator after all.
– Alex Peters
Nov 10 at 14:13
Thank you. In fact, with the
scan
operator I don't actually need the subsequent map
operator after all.– Alex Peters
Nov 10 at 14:13
Thank you. In fact, with the
scan
operator I don't actually need the subsequent map
operator after all.– Alex Peters
Nov 10 at 14:13
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53235649%2fhow-can-i-give-an-rxjs-observable-pipe-access-to-the-original-observables-emiss%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
scan
seems to be what you are looking for:snapshotChanges().pipe(scan((prev, changes) => newImmutableObject(changes, prev), ))
– cartant
Nov 10 at 4:47
Thank you—this is exactly what I was looking for (I was so close!). The learn-rxjs page for
scan
even says “You can create Redux-like state management with scan!” Example 2: Accumulating an object shows almost precisely what I'm trying to achieve.– Alex Peters
Nov 10 at 14:11