Skip to content

Commit

Permalink
fix(createSelector): memoize projector function (#228)
Browse files Browse the repository at this point in the history
Closes #226
  • Loading branch information
03byron authored and MikeRyanDev committed Aug 2, 2017
1 parent c79853b commit e2f1e57
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 4 deletions.
17 changes: 17 additions & 0 deletions modules/store/spec/selector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,23 @@ describe('Selectors', () => {
expect(projectFn).toHaveBeenCalledWith(countOne, countTwo);
});

it('should call the projector function only when the value of a dependent selector change', () => {
const firstState = { first: 'state', unchanged: 'state' };
const secondState = { second: 'state', unchanged: 'state' };
const neverChangingSelector = jasmine
.createSpy('unchangedSelector')
.and.callFake((state: any) => {
return state.unchanged;
});
const projectFn = jasmine.createSpy('projectionFn');
const selector = createSelector(neverChangingSelector, projectFn);

selector(firstState);
selector(secondState);

expect(projectFn).toHaveBeenCalledTimes(1);
});

it('should memoize the function', () => {
const firstState = { first: 'state' };
const secondState = { second: 'state' };
Expand Down
13 changes: 9 additions & 4 deletions modules/store/src/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,24 @@ export function createSelector(...args: any[]): Selector<any, any> {
selector.release && typeof selector.release === 'function'
);

const { memoized, reset } = memoize(function(state: any) {
const memoizedProjector = memoize(function(...selectors: any[]) {
return projector.apply(null, selectors);
});

const memoizedState = memoize(function(state: any) {
const args = selectors.map(fn => fn(state));

return projector.apply(null, args);
return memoizedProjector.memoized.apply(null, args);
});

function release() {
reset();
memoizedState.reset();
memoizedProjector.reset();

memoizedSelectors.forEach(selector => selector.release());
}

return Object.assign(memoized, { release });
return Object.assign(memoizedState.memoized, { release });
}

export function createFeatureSelector<T>(
Expand Down

0 comments on commit e2f1e57

Please sign in to comment.