-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Packages: Add package babel-plugin-transform-with-select #13177
Conversation
Originally included as part of early implementation where namespaces determined by inner nodes from exit of withSelect call expression
I like this optimization 🙂 Because it's an optional optimization, it should be 100% correct and should bail out in situation where correctness is not guaranteed: // we don't know what `passAsParam` selects from, optimizing just for `core/foo` is wrong
withSelect( select => {
return {
a: passAsParam( select ),
b: select( 'core/foo' ).getFoo(),
};
} ) // the current transform doesn't catch call to `s`, optimizing just for `core/foo` is wrong
withSelect( select => {
const s = select;
return {
a: select( 'core/foo' ).getFoo(),
b: s( 'core/bar' ).getBar(),
};
} ) // the current transform doesn't optimize this, but at least does no harm
withSelect( s => {
return {
a: s( 'core/foo' ).getFoo(),
};
} ) Even with this transform, I still like the idea of "single-store select" and would love to see it implemented: withSelect( 'core/foo', store => {
return { a: store.getFoo() };
} ); I like how it's "optimized by default" and doesn't rely on a Babel transform that is somewhat magical.
💯 I'm repeatedly confused by the |
Maybe then, in order to keep this option available, while I'd not implement it here, it might be good for me to at least avoid overloading the "hint" argument to be a singular string, and instead expect it to always be an array if the function is to receive |
Limiting the But even if the
The implementation can always figure out what form is used by a few simple |
No, I suppose not, with that specific order argument at least. It just wasn't clear to me that the difference in usage would be obvious where, as you note, in one case it's a |
There are good ideas here, but with consideration of registry-enhanced selectors as introduced by #13662, the ability to determine store dependencies from a I'd still like to explore options forward here, and suspect it would inherit major parts of what was implemented here, but for now this can't serve as a working solution in its current form. |
Brain-dumping so it doesn't get lost: With the constraints applied to Source: withSelect( ( select ) => {
return select( 'core' ).isRequestingEmbedPreview( '...' );
} )( MyComponent );
// ...
const isRequestingEmbedPreview = createRegistrySelector( ( select ) => ( state, url ) => {
return select( 'core/data' ).isResolving( REDUCER_KEY, 'getEmbedPreview', [ url ] );
} ); Transformed: withSelect( ( select ) => {
return select( 'core' ).isRequestingEmbedPreview( '...' );
}, [ [ 'core', [ 'isRequestingEmbedPreview' ] ] ] )( MyComponent );
// ...
const isRequestingEmbedPreview = createRegistrySelector( ( select ) => ( state, url ) => {
return select( 'core/data' ).isResolving( REDUCER_KEY, 'getEmbedPreview', [ url ] );
} );
isRequestingEmbedPreview.dependencies = [ [ 'core/data', [ 'isResolving' ] ] ]; Then to get all dependencies: const getStoreDependencies = ( dependencies ) => uniq( flatMap(
dependencies,
( [ storeName, selectorNames ] ) => [
storeName,
...selectorNames.map( ( selectorName ) => (
getStoreDependencies( select( storeName )[ selectorName ].dependencies )
) )
]
) );
withSelect = ( mapSelectToProps, dependencies ) => {
const storeDependencies = getStoreDependencies( dependencies );
// [ 'core', 'core/data' ]
}; Certainly not anywhere near as clean a solution as what was previously possible, but there might be a viable implementation somewhere in here all the same. |
To ensure this is not lost, I created a tracking issue at #14150. |
Alternative to: #12877
This pull request seeks to explore using a Babel transform to provide a known subset of reducer keys by which to limit subscriber callbacks for connected components.
See: Proof of Concept
Implementation notes:
Effectively, this adds support for both
subscribe
andwithSelect
to accept an optional second argument, a string or array of strings corresponding to the concerned reducer keys, where the callback is called if and only if the changed store is included in the subset of reducer keys.This is then leveraged by a custom Babel transform plugin which automatically injects this argument based on the calls to
select
within themapSelectToProps
function of awithSelect
-connected component. Unlike #12877, these keys are determined at build-time, rather than at runtime, and is thus not prone to the same false negatives described there.While initial proposals for such an argument starting at #12877 (comment) considered it as the first argument, the changes here propose it as a second argument. Since it's an optional argument, it is easier both to implement and to document to consider as a second argument. At some point, I could imagine this argument could be overloaded as an object of options, on which
reducerKeys
(namespaces
?) would be one of a set of possible properties.Remaining tasks:
Initial performance measurements have shown to be disappointingly non-impacting. I plan to spend more time here, as there should be a noted impact, particularly on initial page load for posts containing non-trivial amounts of content.
After which point, remaining items include:
withSelect
andselect
, rather than the current implementation which depends on hard-coded identifiersreducerKey
doesn't seem strictly accurate to describe this namespace concept, particularly in mind of Redux agnosticism as of wp.data: Split store implementation out from registry. #10289.cc @jsnajdr