-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
[RFC] Add shorthand syntax for mapStateToProps #323
Conversation
Just to give another example from my app. FolderContentContent = connect(state => ({
selectedTags: AppCommonStore.selectedTagsSelector(state),
folderContent: FolderContentStore.folderContentDataSelector(state),
stamples: FolderContentStore.stamplePagesSelectors.stamples(state),
stamplesLoading: FolderContentStore.stamplePagesSelectors.stamplesLoading(state),
stamplesFirstPageLoaded: FolderContentStore.stamplePagesSelectors.stamplesFirstPageLoaded(state)
}))(FolderContentContent); becomes: FolderContentContent = connect({
selectedTags: AppCommonStore.selectedTagsSelector,
folderContent: FolderContentStore.folderContentDataSelector,
stamples: FolderContentStore.stamplePagesSelectors.stamples,
stamplesLoading: FolderContentStore.stamplePagesSelectors.stamplesLoading,
stamplesFirstPageLoaded: FolderContentStore.stamplePagesSelectors.stamplesFirstPageLoaded
})(FolderContentContent); But maybe this can be done outside of react-redux. As this is intended to be used with selectors maybe it is better to add this shorthand syntax to Reselect? FolderContentContent = connect(combineSelectors({
selectedTags: AppCommonStore.selectedTagsSelector,
folderContent: FolderContentStore.folderContentDataSelector,
stamples: FolderContentStore.stamplePagesSelectors.stamples,
stamplesLoading: FolderContentStore.stamplePagesSelectors.stamplesLoading,
stamplesFirstPageLoaded: FolderContentStore.stamplePagesSelectors.stamplesFirstPageLoaded
}))(FolderContentContent); |
Interesting. I’m not opposed to adding this as it mirrors |
I would be +1 to adding this - I agree it's a very common pattern to use and would be great to mirror As for the implementation, it would be great to check whether connect.js: const mapState = isPlainObject(mapStateToProps) ?
wrapMapStateObject(mapStateToProps) :
mapStateToProps || defaultMapStateToProps utils/wrapMapStateObject.js: import invariant from 'invariant'
function mapValues(obj, fn) {
return Object.keys(obj).reduce((result, val, key) => {
result[key] = fn(val, key)
return result
}, {})
}
export default function wrapMapStateObject(mapStateToProps) {
const needsProps = Object.keys(mapStateToProps)
.reduce((useProps, key) => {
const type = typeof mapStateToProps[key]
invariant(
type === 'function',
'mapStateToProps object key %s expected to be a function, instead saw %s',
key,
type
)
return useProps || mapStateToProps[key].length !== 1
}, false)
return needsProps
? (state, props) => mapValues(mapStateToProps, val => val(state, props))
: state => mapValues(mapStateToProps, val => val(state))
} |
@tgriesser thanks for your feedback. Yes it looks like passing props too does not cost much :) Also I'm surprised that you comment positively on this because I've just discovered "structured selectors" of Reselect. I don't find the name very good but it was built after your issue and seems to almost do what I propose here... What would my PR help you solve that you can't already with: Not sure to understand your comment about using a factory. Is this the little thing added recently that almost nobody has to use but that can leverage better performances? ^^ |
It would just prevent the need to wrap with
Yes, but actually now that I think about it again, this wouldn't work in this situation. It'd require the entire selector memoized at the top level, which can only happen with something like |
thanks for your feedback @tgriesser I have no strong opinion on this as the @gaearon tell me when you have decided, I may rework a little my PR with some code of @tgriesser before merge. @tgriesser btw, now that you removed your optimisation that finally does not work (don't know why but I trust you), couldn't we just use |
@gaearon are you still interested by this PR? Tell me and I'll update my PR (because with recent optims I now understand better code suggested by @tgriesser ) |
I can’t promise to merge it but I’d very much like to see a final version of this and play with it. |
@gaearon I've updated my PR with @tgriesser suggestions |
People did not comment here, so comments received on twitter are:
|
I think it's helpful to mention that this PR still allows the current form, so if you don't like it this proposed one, don't use it. |
👍 from me. |
👍 from me too, is this being acknowledged by anyone? |
Fix "action creators" link
We use a wrapper like that within our code so that we dont have to pass mapDispatchToProps all the time. |
@slorber Yes. A couple thoughts:
|
Ok so I'll let the issue open for now Also I think it would be convenient to have a convention and have "selector" in name be automatically stripped. This would allow to write:
and to inject maybe not enough explicit but would significantly reduce boilerplate, and allow to keep "selector" in name of methods |
@gaearon @jimbolla @tgriesser it's been a while that this PR is open and it seems I'm not the only one wanting this Would this get merged if I port the PR to work on master, polish it a bit and add better documentation? |
I would like this. Can it also support "factory" style? For example:
I'm thinking this would be optimal for use with reselect where one will probably do:
|
Hi @jimbolla For now I've not really used these factories, do you refer to this? Because what I see as signature in doc is Also could we mix both styles?
I'm not sure it would be easy to detect weither makeGetSometThing is a normal selector or a factory as both are functions |
@slorber : yeah, that's what Jim is referring to. I have an example of using the factory syntax here : https://www.reddit.com/r/reactjs/comments/5dxasp/any_deepdiveadvanced_tutorials_on_reselect/ |
@markerikson I see your example but still it's different from what @jimbolla show in his code snipped
VS
Maybe I'm missing something, but can you give me the verbose version of the following snippet?
|
I know. What I'm saying (and I think Jim is too) is that currently, passing an actual function as the |
Hmmm as far as I know if I get an object with functions as values, I can't know if the function will be a selector or a selector factory. At least I don't know how to make a distinction between I took a look at current factory implementation and noticed this comment:
This works fine because mapState is assumed to return an object, so when it does not and return a factory, we can init the selector and call it, which will end-up by returning the object we want to inject. But in current scenario, the final selector is for a given propName, not for all the component props, so the expected value can be of any type, including functions, so it's harder to detect we are in the case of a factory (current test is What I mean is that if we are going to implement this feature, it will not work if the user is currently injecting functions through mapStateToProps like this:
I don't really have a usecase for why a user might do something like that so please tell me if there is any? for mapDispatchToProps it's clear that the user will want to inject functions so how can we know if that function is a factory or the function the user wanted to inject? So, I we could support factory functions in mapState but not mapDispatch, but it requires assuming that user is not injecting functions through mapState (who's doing that anyway?) |
Hi @slorber @markerikson and @jimbolla , I wasn't aware that this PR was here and I opened a similar PR that -obviously- got immediately closed by @markerikson. Sorry about that, I did check in the opened issues if there was a feature request for this and I saw nothing. I should have also checked in the opened PRs... my bad! I would really like to see this enhancement shipped and I'm pretty sure that I know how to solve the "factory style" issue that seems to be blocking this PR. Is it cool if I solve that issue in my branch? Or should I try to add a commit to this branch? |
Hi again @slorber @markerikson and @jimbolla ! I've added the following commit into my branch which makes the I've also added the following test to make sure that it works... and it does 😄 Since this PR seems to be stale, would it be ok for me to suggest that I make the PR from my branch which also has no conflicts with master? |
as long as it works i'm ok with that but it's not my decision to merge :) |
Would love this right about now! :) |
Hi, Still wanting this feature and it seems I'm not alone :) I'm free to rework the PR if needed, just ping me when the decision is made. |
I have no objections. |
I'm fine with it to. This PR just needs a rebase, since things have changed quite a bit since it was created. |
The rebase was a bit complicated so I merged manually all changes to a new PR: #723 |
connect(map<selectors>, map<actionCreators>) seem like a good starting point for beginners. It is:
It seems to be a saner starting point than connect(kindOfSelector, map<actionCreators> ). |
Hi,
This is a proposal for a shorthand syntax for connect.
I use Reselect and connect and I almost never use the props parameter in mapStateToProps.
I'd like this shorthand syntax so that instead of writing:
we could write: