-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
createSelector() not memoizing correctly #226
Comments
OK, I can confirm that this is an issue. I understand the desire not to have ngrx dependent on other packages, but these sorts of bugs could be avoided by not trying to reinvent things like |
One other If you have an example of this bug in your app, can you try building it with --prod (if you are using angular cli), and see if the problem goes away? It did for me. |
Just did a |
I've created a failing test. How am i able to submit it? Actually, one could argue that some tests are wrong: For example: it('should memoize the function', () => {
const firstState = { first: 'state' };
const secondState = { second: 'state' };
const projectFn = jasmine.createSpy('projectionFn');
const selector = createSelector(
incrementOne,
incrementTwo,
incrementThree,
projectFn
);
selector(firstState);
selector(firstState);
selector(firstState);
selector(secondState);
expect(incrementOne).toHaveBeenCalledTimes(2);
expect(incrementTwo).toHaveBeenCalledTimes(2);
expect(incrementThree).toHaveBeenCalledTimes(2);
expect(projectFn).toHaveBeenCalledTimes(2);
});
beforeEach(() => {
countOne = 0;
countTwo = 0;
countThree = 0;
incrementOne = jasmine.createSpy('incrementOne').and.callFake(() => {
return ++countOne;
});
incrementTwo = jasmine.createSpy('incrementTwo').and.callFake(() => {
return ++countTwo;
});
incrementThree = jasmine.createSpy('incrementThree').and.callFake(() => {
return ++countThree;
});
}); https://github.com/ngrx/platform/blob/master/modules/store/spec/selector.spec.ts#L44 |
I think the source of the issue is that memoization is based on the (whole) state and not on the value of the selectors. https://github.com/ngrx/platform/blob/master/modules/store/spec/selector.spec.ts#L44 |
I think that you are mistaken in your first point. projectFn should only be called 2 times, precisely because the memoization is based on the whole state. And I believe that is the correct behavior--if the whole state is identical, the selector should be able to skip ALL the selectors and the projector and just return the same result as last time. The problem is that it should probably also be checking all the results of the selectors, and skipping the projector if those are also identical. It doesn't appear to be doing that. I haven't dug into the reselect code, but my guess is that reselect does this. |
I'm submitting a...
What is the current behavior?
The projector fn passed to createSelector() is invoked even when its arguments remain unchanged.
Expected behavior:
The projector fn should be called only when one of its arguments change.
Minimal reproduction of the problem with instructions:
http://plnkr.co/edit/GEdUHwk3XEnHHwmPVMSr?p=preview
When you click increase/decrease buttons you can see in the console that the projector function executes but its arguments didnt change.
or in short summary:
interestingly when wrapping the projector fn in createSelector as well, i get the desired behavior:
Version of affected browser(s),operating system(s), npm, node and ngrx:
Chrome 59
OS X El Capitan
npm 3.10.8
node 6.9.1
ngrx 4.0.0
The text was updated successfully, but these errors were encountered: