-
Notifications
You must be signed in to change notification settings - Fork 500
refactor(Selectors): Use reselect for selectors instead of Rx operators #75
Conversation
Other than having to include an additional library are there any downsides to this approach? I'm only seeing wins, both in performance and readability. |
Are there not any combinations of rxjs operators that would accomplish this? Not arguing against the change, but asking for my own knowledge. |
@brandonroberts Not really. @btroncone Can't think of any major downsides, though I did think of another upside: memoization works across multiple subscriptions. |
Merging this in :) |
Am I correct that the reselect library is only actually being used for selectors such as |
Would reselect be faster than the following solution? export function getIds(state$: Observable<State>) {
return state$.select(state => state.ids);
}
export function getEntities(state$: Observable<State>) {
return state$.select(state => state.entities);
}
export function getAll(state$: Observable<State>) {
return Observable
.combineLatest(getIds(state$), getEntities(state$), (ids, entities) => ids.map(id => entities[id]))
.distinctUntilChanged()
} If so, you could just create an operator which combines these two operators, right? You could call it something like |
@marklagendijk By default |
When I wrote my own rxjs implementation of selectors for NGRX/Store I got around this problem by adding a debounce of 1 tick for selectors that take multiple sources. |
@mrpmorris that's okay if you're okay with triggering an extra zone run. Rather than createSelector, why not create an operator selectAll that uses distinctUntilChanged that checks each input? Then you don't have to go outside RxJS. One of the reasons I switched from Redux + Reselect is because RxJS operators are much cleaner to me than memoized selectors. Here's an example implementation:
Here's some example output that creates:
Here's the demo: https://goo.gl/G9uPT5 |
In a real world application we've discovered that the performance cost of using Rx operators to perform joins can be significantly higher in comparison to memoized functions.
For example, consider this group of selectors:
The characteristics of the three selectors in marble diagrams will look like this:
Importantly, on the frame where both IDs and Entities changes the
combineLatest
observable emits twice: once for each update. This means that the map function joining the two pieces of state will be called twice in the same tick and each subscriber will be notified twice.This PR refactors the selectors to use reactjs/reselect for fast, memoized selectors.
The above three selectors can rewritten like this:
Applying selectors is done with
select
instead oflet
:cc @btroncone @dpsynapse