-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Framework: Don't bind selectors to state in connect
#14024
Comments
Thanks @mcsf
I think it'd be worthwhile to add an eslint warning as well, with a link to why we shouldn't be using this pattern. I've seen folks attempt to use this anti-pattern in PRs before. |
@gwwar totally agree, and it should also cover cases of explicit
function declaration.
|
Nice! I don't think I've seen that pattern being used too much, and I hope we won't be seeing it anymore too 😉 |
Can we close this? Looks like everything is done. |
Antipattern
The following is a by-product on the work to remove SitesList, chiefly #13094. I'd like to have it tackled before the anti-pattern spreads.
As of this writing:
Context
A few instrumental view-layer pieces that deal with sites were, under the SitesList paradigm, expecting from that library the ability to access any property of any site from the entire list of sites at any moment in Calypso's lifecycle (whether in the views, pre-, mid-, post-render, or elsewhere), and notably within component methods.
This clashes with our Redux-era way of:
connect
siteId
instead ofsite
, leaving it to the descendant(s) to obtain the remainder viaconnect
.To avoid more blockage of #13094, the
selector.bind( null, state )
anti-pattern was introduced as a very short-term fix. There are concrete technical reasons for why this is very bad. I was trying to find a longish comment I left on some PR recently where I detailed this a bit more, but the gist of it is that 1) there is the cost of instantiating a bound function on eachmapState
call, meaning every time global state changes, and on top of that 2) we lose the ability to shallowly compare old and new props on those connected components to avoid re-rendering, since the bound selector has a new reference each time it is instantiated.Solution
Edit: Even though the rationale below has grounds, since a lot of SitesList-era behavior revolves around holding a lot of duplicate and/or derived state, we should take the opportunity to simplify logic in these components whenever possible. For instance:
navigateToSite
in SiteSelector: Remove selector state binding #14028.Feel free to ignore the following.
A common pattern in these remaining occurrences of selector binding is that the selector is required within the component because the data to be passed to the selector depends on component state. For instance, inSitesDropdown
:A way to solve this is by having an intermediate layer that can pass this state intoconnect
'smapState
using a state-holding component:A specialized version of this pattern was used in 5ad8cee so thatSiteSelector
could search sites based on user input.Overthinking?
This lead me a few weeks ago to make aconnectWithState
interface that would solve this implicitly for cases likeSitesDropdown
. See gist:The text was updated successfully, but these errors were encountered: