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
WIP 1.0.0 (Configurable memoize / variadic dependencies / pass props to selector) #35
Conversation
items => items.reduce((acc, item) => acc + item.value, 0) | ||
); | ||
``` | ||
|
||
### Selector Usage | ||
### Using Selectors with React-redux |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's capitalize as React Redux (like in docs)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed
@speedskater @faassen @heyimalex (and anyone else reading!) If anyone has some spare time on their hands it would be great if I get could get some opinions on this PR.
|
I think everybody's waiting for “how to use this with React Redux |
The last couple of examples for |
const totalSelector = createSelector( | ||
state => state.shop.items, | ||
items => items.reduce((acc, item) => acc + item.value, 0) | ||
// A selector is also passed props as the last parameter into the resultFunc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this result in problems, as the selector suddenly depends on all properties. Therefore changing whenever a single property - which might not influence the selector at all - changes.
Wouldn't it be better to have the following signature
createSelector(
state, props => state.values.value1,
state, props => state.values.value2,
state, props => props.value3,
value1, value2, value3 => value1 + value2 + value3
)
@speedskater Thanks for the feedback. Inspired by your first suggestion, I simply changed |
@ellbee Thanks. Do you really think we need multiple arguments? I think the composite object instead of a state might be a really elegant solution. In combination with destructuring assignment it seems really powerful. Or am I missing something? |
@speedskater I went with multiple arguments because it makes I'm not sure I see the advantages of the composite object being that great, but I am open to be persuaded. |
@ellbee I get your point. On the other hand using the composite object, the signature of a selector doesn't change at all. I think it should even work with the current version of reselect. I think having a single object as an argument encourages better composability and flexibility. var mySelector = createSelector(
([ state, props ]) => state.value1,
([ state, props ]) => state.value2,
([ state, props ]) => props.value3,
value1, value2, value3 => value1 + value2 + value3
);
mySelector([state, props]); Using this pattern the arguments of In combination with the nice features you just added like different memoization functions i think it allows even more usage scenarios. So for me the main advantages for this kind of pattern are:
If we keep selector simple I think we should emphasize this flexiblity in the documentation. Hopefully this will help the users with What do you think ? |
@speedskater How does the array (or object) parameter work with the connect decorator? You couldn't just pass the selector straight in if you wanted to access the props right? I feel like I am missing something. What if we don't take an opinion on this and have a variadic parameter list. Then it would be possible to use (state, props), ({state, props}), ([state, props]) or whatever else. export function createSelectorCreator(memoize, ...memoizeOptions) {
return (...selectors) => {
const memoizedResultFunc = memoize(selectors.pop(), ...memoizeOptions);
const dependencies = Array.isArray(selectors[0]) ?
selectors[0] : selectors;
return (...args) => {
const params = dependencies.map(dependency => dependency(...args));
return memoizedResultFunc(...params);
};
};
} |
@elbee You are right directly passing the selector without some kind of wrapper is impossible. (haven't thought about it this way). |
c09d3ff
to
b6020b9
Compare
f9fd02d
to
96475be
Compare
Hi @ellbee and @speedskater, I'm running some tests on the latest version of reselect yet, and the last commit (31a30bd) breaks the ability for You can find the reason here: As you can see,
I also took a look at all the other I created a pull request that reverts the change: #40 Awesome work here btw, loving it :) |
c74788e
to
b66b077
Compare
I'm certainly not up to date on this issue, but I found it a bit odd that defaultMemoize has a valueEquals parameter. Shouldn't that be "createMemoize" or something? Though of course we should make sure people can create memoize functions without using it. |
@faassen You mean rename |
In essence, |
Oh, and the thinking behind giving Beforeimport { isEqual } from 'lodash';
import { createSelectorCreator } from 'reselect';
const deepEqualsSelectorCreator = createSelectorCreator(isEqual); Afterimport { isEqual } from 'lodash';
import { createSelectorCreator, defaultMemoizeFunc } from 'reselect';
const deepEqualsSelectorCreator = createSelectorCreator(
defaultMemoizeFunc,
isEqual
); |
Sorry for the late response but I have been on a short holiday for the last days. @volrath, @ellbee As far as i undestand it is not that simple. As far as i know, the reason that the signature check was implemented in react-redux was to prevent such calls. But i think this check should be done by the selector and not by the higher order component. Another possiblity would be to create a selector with the same arity as the selector with the largest arity. The problem is that creating such a function is quite expensive and i would vote highly against it. @gaearon what do you think. Could we remove the signature check in react-redux from the connect HOC and let the selector alone decide whether it does resepect props or not? This would be equal to a reselect selector like this. createSelector((state, props) => state, state => .....); |
@speedskater Hey, no worries. Hope you had a good holiday. I am aware that the selector is going to be called every time the props change whether we are using them or not. My thinking is that if the dependencies aren't using the props, a prop change won't cause the results function to be re-run because non of the parameters to the results function will have changed. For this reason I am presuming it won't be too big a performance hit. Am I missing something? |
@ellbee you are right. I think it wouldn't be a performance hit at all. I even think, that the connect method should always provide the props parameter. As it is the duty of the selector to decide whether its result changes or not. |
a8bac34
to
2233680
Compare
@speedskater (and everyone else), is there anything you think should be looked at before releasing 1.0.0? I'd like to get the release done in the next couple of days if everyone is happy. |
@ellbee Thanks for your effort. From my point of view I think we could ship 1.0.0. |
Nice work! |
👍 ! |
Great: 👍 ! |
Work in progress experiments to address issues #7 , #20 , #27. The API section of the README has some examples.
There is one breaking change. createSelectorCreator now takes a memoize function instead of a valueEquals function.