-
-
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: I've created a variant of connect() that is a tailored for using with reselect #405
Comments
You've clearly put a bunch of work into this, but to be honest I'm still not really clear on what your issues are with the standard The one thing I'm grasping so far is that you want to state available when binding action creators, but as far as I've seen that's a pretty niche use case, and |
@markerikson In addition to what you mentioned, the other issue I started running into was when I was using createSelector in mapStateToProps, mapDispatchToProps and mergeProps, because they each have different parameters, I had to organize my selectors by which method they aligned with. (Using createSelector to memoize my functions is useful for partially applying args from state/props, so that a new function isn't created every time an unrelated prop is changed.) It also looks like mergeProps doesn't have the same "advanced" option like the other two, so any selectors I want to use in there have to be singletons instead of being bound to the lifetime of the component instance. So I started looking at the source for connect() to see if it would be possible to modify it to just supply dispatch as a 3rd param to mapStateToProps, but I found the source for connect() to be very difficult to mentally parse. There's a lot of magic in there to track all the various moving parts. I don't think I could make the changes I'd like to connect() without breaking something. There's 10 "cache" fields on the component and another 5 temp variables in the render() method mixed inside a lot of if/else blocks. That's why I decided to create my own implementation using reselect to track all those moving parts instead. |
Fair enough. The implementation of Beyond that, I'm not seeing anything specifically actionable about this issue. It's not a bug or feature request against React Redux itself, and since it's basically a one-off implementation for your own use case, I'm not quite sure what feedback you're looking for. I'll leave the issue open for the moment just so it's a bit more visible if someone's browsing the repo issues list, but will probably close soon if there's no further discussion. |
I just whipped this up and haven't tested it at all, but this could be wrapper around my export function connectClassic(
mapStateToProps,
mapDispatchToProps,
mergeProps,
{
pure = true,
withRef = false,
}
) {
function selectorFactory() {
const ownPropsSelector = createShallowEqualSelector(
(_, props) => props,
props => props
);
function getStatePropsSelector() {
if (!mapStateToProps) return () => null;
return createSelector(
state => state,
ownPropsSelector,
mapStateToProps
);
}
function getDispatchPropsSelector() {
if (!mapDispatchToProps) return (_, __, dispatch) => ({ dispatch });
if (typeof mapDispatchToProps === 'function') {
return createSelector(
(_, __, dispatch) => dispatch,
ownPropsSelector,
mapDispatchToProps
);
}
return createSelector(
(_, __, dispatch) => dispatch,
dispatch => bindActionCreators(mapDispatchToProps, dispatch)
);
}
return createShallowEqualSelector(
getStatePropsSelector(),
getDispatchPropsSelector(),
ownPropsSelector,
mergeProps || defaultMergeProps
);
}
return connectToStore(
selectorFactory,
{
pure,
withRef,
getDisplayName: name => `Connect(${name})`,
recomputationsProp: null,
shouldIncludeOriginalProps: !mergeProps,
shouldUseState: Boolean(mapStateToProps),
}
);
} I still need to hoist statics, support hot reloading, and add some argument validation; but at that point I think I'd have feature parity with the existing implementation. I'll need a moment to look at those linked issues to see how they'd impact my implementation. I agree there's nothing directly actionable here for react-redux, so the issue could be closed, but unfortunately I don't know of a more appropriate place to have this discussion. I would love to get more eyeballs on this from devs that have different requirements than my own. |
Yeah, I do follow the reasoning for posting this here. Perhaps raise the question over in Reactiflux, just to see if anyone else has feedback? |
@markerikson So I wrote a version of |
…ter-pack add example webapp-starter-pack
I wasn't quite happy with the API for
connect()
so I went about recreating my own. A few design goals:An example of starting with no
reselect
selectors and building up from there:Version 1: this works, but the onLoad arrow function will be recreated everytime props/state change:
Version 2: uses reselect's
createSelector
to solve the function issue, but gets verbose:Version 3: this version users createStructuedSelector to make it less verbose:
Version 4: utilize
dispatchable
to make the actionCreator call less verbose:Version 5: make createStructuredSelector implicit if a plain object is returned instead of a function
Current source with some explanatory comments is here
The main exports are
connectToStore(selectorFactory, options)
anddispatchable(actionCreator, ...selectorsToPartiallyApply)
.connectToStore
is the variant of react-redux'sconnect()
whiledispatchable
wraps action creators in a selector that binds it to dispatch.The signature for selectorFactory is
() => (state, props, dispatch) => {newProps}
. Anyreselect
selectors, including those created bydispatchable
created inside the factory function are scoped to that component instance.selectorFactory
has a shorthand that I use 99% of the time:() => {inputSelectors}
, whereinputSelectors
is passed to createStructuredSelector to create the selector.I think it's coming along nicely, although I don't yet have hot reloading support (I'm not sure what that will entail) or any argument validation. Any constructive criticism would be welcome.
The text was updated successfully, but these errors were encountered: