Selector proposal #169

Closed
wants to merge 5 commits into
from

Conversation

7 participants
@speedskater

Hi,

Our proposal for issue 47. It should support the same functionality as nuclear-js getters.

Robert

.gitignore
@@ -6,3 +6,4 @@ lib
coverage
react.js
react-native.js
+.idea

This comment has been minimized.

@aaronjensen

aaronjensen Jun 23, 2015

Contributor

For non-project specific things like this, you might consider a global gitignore: https://help.github.com/articles/ignoring-files/#create-a-global-gitignore

@aaronjensen

aaronjensen Jun 23, 2015

Contributor

For non-project specific things like this, you might consider a global gitignore: https://help.github.com/articles/ignoring-files/#create-a-global-gitignore

This comment has been minimized.

+ expect(arrayEqual(array, undefined)).toBe(false);
+ });
+ });
+});

This comment has been minimized.

@aaronjensen

aaronjensen Jun 23, 2015

Contributor

@speedskater can you check your editor settings? It's best to end files w/ newlines. There are a few files in here that don't have them.

@aaronjensen

aaronjensen Jun 23, 2015

Contributor

@speedskater can you check your editor settings? It's best to end files w/ newlines. There are a few files in here that don't have them.

This comment has been minimized.

@speedskater

speedskater Jun 23, 2015

New lines fixed.

@speedskater

speedskater Jun 23, 2015

New lines fixed.

+import { createSelector, createBuffered } from 'redux';
+
+export let todoSelector = createSelector('todos');
+export let numberOfTodos = createSelector(todoSelector, createBuffered(todos => todos.length));

This comment has been minimized.

@aaronjensen

aaronjensen Jun 23, 2015

Contributor

This may have been discussed, or I may be missing something obvious here, but why separate creating selectors from memoization?

@aaronjensen

aaronjensen Jun 23, 2015

Contributor

This may have been discussed, or I may be missing something obvious here, but why separate creating selectors from memoization?

+ render() {
+ return (
+ //use your predefined selectors
+ <Connector select={state => ({

This comment has been minimized.

@aaronjensen

aaronjensen Jun 23, 2015

Contributor

What if select actually took selectors in the same format as nuclear-js getters, that is an array. So this would be:

select={['todos', todos => todos.length]}

You could still import an array selector from somewhere else, and testing it would require you to call createSelector, but it would allow the individual connector to worry about memoziation (not sure if this is better or not...)

@aaronjensen

aaronjensen Jun 23, 2015

Contributor

What if select actually took selectors in the same format as nuclear-js getters, that is an array. So this would be:

select={['todos', todos => todos.length]}

You could still import an array selector from somewhere else, and testing it would require you to call createSelector, but it would allow the individual connector to worry about memoziation (not sure if this is better or not...)

This comment has been minimized.

@aaronjensen

aaronjensen Jun 23, 2015

Contributor

@gaearon something like this would require some sort of support in redux itself, which could just be something along the lines of connector/select middleware

@aaronjensen

aaronjensen Jun 23, 2015

Contributor

@gaearon something like this would require some sort of support in redux itself, which could just be something along the lines of connector/select middleware

This comment has been minimized.

@speedskater

speedskater Jun 23, 2015

Our decion was that a selector is a function which translates an input state into an output representation. The best solution would be to just combine the selectors as plain functions.

let todoSelector = state => state.todos;
let todoCountSelector = state => todoSelector(state).length;

The main drawback in this case is that you can only memoize on individual function parameters not on the parts of the state which are used in the selector itself.
To preserve functional semantics the construct using the createSelector was chosen in favor of passing arrays around.

The reason that it was chosen to make memoization explicit was to make it a decision to the user wether she wants to have a material view on her state or not.

@speedskater

speedskater Jun 23, 2015

Our decion was that a selector is a function which translates an input state into an output representation. The best solution would be to just combine the selectors as plain functions.

let todoSelector = state => state.todos;
let todoCountSelector = state => todoSelector(state).length;

The main drawback in this case is that you can only memoize on individual function parameters not on the parts of the state which are used in the selector itself.
To preserve functional semantics the construct using the createSelector was chosen in favor of passing arrays around.

The reason that it was chosen to make memoization explicit was to make it a decision to the user wether she wants to have a material view on her state or not.

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jun 23, 2015

Collaborator

This is interesting. We need to choose what we want to support and what we want to push into userland, and whether we want to have “blessed” userland packages.

If @acdlite, @faassen, @goatslacker could give some feedback on what they think what core/non-core distinction would be appropriate, that would be awesome. Personally, I'm leaning to create a Github org and have a few supported add-ons like this one that would be versioned separately.

Collaborator

gaearon commented Jun 23, 2015

This is interesting. We need to choose what we want to support and what we want to push into userland, and whether we want to have “blessed” userland packages.

If @acdlite, @faassen, @goatslacker could give some feedback on what they think what core/non-core distinction would be appropriate, that would be awesome. Personally, I'm leaning to create a Github org and have a few supported add-ons like this one that would be versioned separately.

@aaronjensen

This comment has been minimized.

Show comment
Hide comment
@aaronjensen

aaronjensen Jun 23, 2015

Contributor

nuclear-js keypaths can be arrays too, so you can do something like:

// state: { foo: { bar: 1 }, baz: { fab: 2 } }
[['foo', 'bar'], ['baz', 'fab'], (foobar, bazfab) => ...]
Contributor

aaronjensen commented Jun 23, 2015

nuclear-js keypaths can be arrays too, so you can do something like:

// state: { foo: { bar: 1 }, baz: { fab: 2 } }
[['foo', 'bar'], ['baz', 'fab'], (foobar, bazfab) => ...]
@leoasis

This comment has been minimized.

Show comment
Hide comment
@leoasis

leoasis Jun 23, 2015

Contributor

I agree with @aaronjensen that there needs to be some kind of Connector level memoization. Say you generally use the same selector in two components but with different parameters, then you won't be making use of the cached results since one will be invalidating the other.

Contributor

leoasis commented Jun 23, 2015

I agree with @aaronjensen that there needs to be some kind of Connector level memoization. Say you generally use the same selector in two components but with different parameters, then you won't be making use of the cached results since one will be invalidating the other.

@speedskater

This comment has been minimized.

Show comment
Hide comment
@speedskater

speedskater Jun 23, 2015

@leoasis That's true but isn't it a different selector in this case?
Because both selectors operate on the same global state. Either it is the same or not.

@leoasis That's true but isn't it a different selector in this case?
Because both selectors operate on the same global state. Either it is the same or not.

@leoasis

This comment has been minimized.

Show comment
Hide comment
@leoasis

leoasis Jun 23, 2015

Contributor

Yeah but I was talking mainly about parametrized selectors. Something like isTodoCompleted(todoId)

If I use createBuffered to define that selector, it will get invalidated by different todoIds

Contributor

leoasis commented Jun 23, 2015

Yeah but I was talking mainly about parametrized selectors. Something like isTodoCompleted(todoId)

If I use createBuffered to define that selector, it will get invalidated by different todoIds

@speedskater

This comment has been minimized.

Show comment
Hide comment
@speedskater

speedskater Jun 23, 2015

@leoasis That's true but i would argue that this still can be solved using the proposed selector approach.
If todoId is part of the central state, there must be a selector available selecting it.
In case the selector depends on a component property it would have to be composed in the component itself or created on the fly as an input of the selector depends on the component property instead of the central state.

createSelector(todoSelector, state => todoId, createBuffered(isTodoCompleted));

It could furthermore be argued, that it isn't a selector at all as it is not a pure function on the central redux state.

@leoasis That's true but i would argue that this still can be solved using the proposed selector approach.
If todoId is part of the central state, there must be a selector available selecting it.
In case the selector depends on a component property it would have to be composed in the component itself or created on the fly as an input of the selector depends on the component property instead of the central state.

createSelector(todoSelector, state => todoId, createBuffered(isTodoCompleted));

It could furthermore be argued, that it isn't a selector at all as it is not a pure function on the central redux state.

@leoasis

This comment has been minimized.

Show comment
Hide comment
@leoasis

leoasis Jun 23, 2015

Contributor

Yeah i guess you're right, makes sense.

Contributor

leoasis commented Jun 23, 2015

Yeah i guess you're right, makes sense.

@faassen

This comment has been minimized.

Show comment
Hide comment
@faassen

faassen Jun 24, 2015

I started to write a lot of stuff on extensions and core, but that's going to be rather long so I may write a blog entry about that sometime. A separate github org with core and extensions in it makes sense. There is some expectation that the maintainers of the core care about the extensions the organization. There's no need to go for an extension just so you get modularity, though.

Oh and don't create some kind of contrib or addons directory in your package as that's the worst of both worlds. See here http://blog.startifact.com/posts/against-contrib.html

faassen commented Jun 24, 2015

I started to write a lot of stuff on extensions and core, but that's going to be rather long so I may write a blog entry about that sometime. A separate github org with core and extensions in it makes sense. There is some expectation that the maintainers of the core care about the extensions the organization. There's no need to go for an extension just so you get modularity, though.

Oh and don't create some kind of contrib or addons directory in your package as that's the worst of both worlds. See here http://blog.startifact.com/posts/against-contrib.html

@gaearon

This comment has been minimized.

Show comment
Hide comment
@gaearon

gaearon Jul 6, 2015

Collaborator

Hi again!

I don't currently plan to bring it as is to Redux, but I asked @faassen and @ellbee to play around with it, and after tweaking the API, they came up with reselect. I think it solves the same problem as this PR, so I'm closing it in favor of reselect.

Thanks again for your PR, as it served as the starting point for reselect.

Collaborator

gaearon commented Jul 6, 2015

Hi again!

I don't currently plan to bring it as is to Redux, but I asked @faassen and @ellbee to play around with it, and after tweaking the API, they came up with reselect. I think it solves the same problem as this PR, so I'm closing it in favor of reselect.

Thanks again for your PR, as it served as the starting point for reselect.

@gaearon gaearon closed this Jul 6, 2015

@speedskater

This comment has been minimized.

Show comment
Hide comment
@speedskater

speedskater Jul 6, 2015

Nice that @faassen and @ellbee have taken over. But imho a comment to our original source code would have been fair.

Nice that @faassen and @ellbee have taken over. But imho a comment to our original source code would have been fair.

@ellbee

This comment has been minimized.

Show comment
Hide comment
@ellbee

ellbee Jul 6, 2015

Member

@speedskater I absolutely agree. We'll get that sorted out today. Sorry.

cc @faassen

Member

ellbee commented Jul 6, 2015

@speedskater I absolutely agree. We'll get that sorted out today. Sorry.

cc @faassen

@speedskater

This comment has been minimized.

Show comment
Hide comment
@speedskater

speedskater Jul 6, 2015

@ellbee thanks :). And nice work that you streamlined the selector approach into a pure functional one.

@ellbee thanks :). And nice work that you streamlined the selector approach into a pure functional one.

@faassen

This comment has been minimized.

Show comment
Hide comment
@faassen

faassen Jul 6, 2015

@speedskater I agree as well you deserve a lot of the credit: we basically just looked at your code and refactored it a bit. We discussed adding credits in the codebase already, but we did this as the hackathon before React Europe and after that there was the conference, so we had little chance for followup yet.

faassen commented Jul 6, 2015

@speedskater I agree as well you deserve a lot of the credit: we basically just looked at your code and refactored it a bit. We discussed adding credits in the codebase already, but we did this as the hackathon before React Europe and after that there was the conference, so we had little chance for followup yet.

@faassen

This comment has been minimized.

Show comment
Hide comment
@faassen

faassen Jul 6, 2015

@speedskater, @ellbee already added your github nick to the README. I now also added a CREDITS file to track contributions. I've used your github nick as I don't know your real name; if you want me to put in your real name let me know.

faassen commented Jul 6, 2015

@speedskater, @ellbee already added your github nick to the README. I now also added a CREDITS file to track contributions. I've used your github nick as I don't know your real name; if you want me to put in your real name let me know.

@speedskater

This comment has been minimized.

Show comment
Hide comment
@speedskater

speedskater Jul 7, 2015

Thanks for adding. Regarding the realnames could you please add my realname Robert Binna and the realname of my coworker Philip Spitzlinger to the credits as the initial draft was the result of a pair programming session.

Thanks for adding. Regarding the realnames could you please add my realname Robert Binna and the realname of my coworker Philip Spitzlinger to the credits as the initial draft was the result of a pair programming session.

@faassen

This comment has been minimized.

Show comment
Hide comment
@faassen

faassen Jul 7, 2015

Ah, I see someone already added the real names to CREDITS. Great!

faassen commented Jul 7, 2015

Ah, I see someone already added the real names to CREDITS. Great!

@clearjs

This comment has been minimized.

Show comment
Hide comment
@clearjs

clearjs Jul 7, 2015

Contributor

Formally, you'd also need to agree on the license (MIT?).

Contributor

clearjs commented Jul 7, 2015

Formally, you'd also need to agree on the license (MIT?).

@faassen

This comment has been minimized.

Show comment
Hide comment
@faassen

faassen Jul 7, 2015

Ah, good point. I've just added a MIT license. Thanks!

faassen commented Jul 7, 2015

Ah, good point. I've just added a MIT license. Thanks!

@Nbsaw Nbsaw referenced this pull request in Nbsaw/notes Feb 16, 2018

Open

reselect - selector library for redux #42

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment