-
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
Stepper: Apply extended props to calypso_signup_start
. Update tailored-ecommerce
flow
#93941
Conversation
Jetpack Cloud live (direct link)
Automattic for Agencies live (direct link)
|
Here is how your PR affects size of JS and CSS bundles shipped to the user's browser: App Entrypoints (~25 bytes added 📈 [gzipped])
Common code that is always downloaded and parsed every time the app is loaded, no matter which route is used. Sections (~327 bytes removed 📉 [gzipped])
Sections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to. Async-loaded Components (~213 bytes removed 📉 [gzipped])
React components that are loaded lazily, when a certain part of UI is displayed for the first time. Legend What is parsed and gzip size?Parsed Size: Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory. Generated by performance advisor bot at iscalypsofastyet.com. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Man this is becoming so niccce.
const recur = useSelect( | ||
( select ) => ( select( ONBOARD_STORE ) as OnboardSelect ).getEcommerceFlowRecurType(), | ||
[] | ||
); | ||
|
||
return { recur }; | ||
return useMemo( () => ( { [ STEPPER_TRACKS_EVENT_SIGNUP_START ]: { recur } } ), [ recur ] ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should save people who don't use useMemo
by serializing the object somehow before passing it to the effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the same feeling. By definition though, useTracksEventProps
being a hook, it can have internal state or rerun/react to changes in external state (such a store), so it will force rerenders up the tree as per the natural life cycle.
I'm really not too fond of "hacking" away from the normal data flow in React. Perhaps we need to accept the reality and ask consumers to be smart about it. Otherwise, we can turn the hook to a regular function and that should make it clear that it won't be deviant to rerunning on state changes. (Edit: i think that's just not gonna work at all)
I think that's more or less my thought process in general
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I meant the above as in more generally about the risk involved (as in connection to your comment in the other PR)
We can certainly do some sort of string-serialization on framework end to avoid same object not being memoized. Just the reality doesn't change that state changing from here will propagate up
input?: Record< string, unknown >; | ||
} | ||
|
||
const useSnakeCasedKeys = ( { input }: Params ) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we call this something like useMemoizedSnakeCasedKeys
or something indicative?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I'm not sure, but I wouldn't mind if that really helps. It sounds too low-level to me. Hooks not memoizing ought to be the exception for the most part, not the norm. If there's an object being returned (similarly with state selectors) they ought to memoize the value to avoid recomputing and ensuring referential integrity (avoiding rerenders up the chain). It feels weird to be calling hooks useMemoizedFoo
, useMemoizedBar
, etc.
p.s. there's a test added that acts as a fairly tough restriction/guarantee that this will be a memoized value.
} | ||
|
||
const useSnakeCasedKeys = ( { input }: Params ) => { | ||
return useMemo( () => input && ( convertToSnakeCase( input ) as Params[ 'input' ] ), [ input ] ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I bet people will pass this function fresh objects every render and the useMemo
won't be able to function. Maybe we can make a clever hook that memoizes objects by serializing keys and values somehow. Or use KCD's https://github.com/kentcdodds/use-deep-compare-effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's definitely a possibility, but I think it sounds like a general issue with Stepper (and more generally) e.g. every single hook that's exposed to flows for implementation is subject to this concern - so is everything built on top to transform. It's almost like we need to wrap everything with such a clever serializer.
I think there may be value in something like that, but:
- doing it here feels a bit random i.e. why only this hook? It needs to be planned out. I would also think a provision to "disable" something like that to be of value.
- it will become a default performance penalty that happens on every update that goes through these hooks. We'd effectively need to "ban" use of
useMemo
and resolve to this default implementation that wraps everything. Why not trust that flows will be smart about it (especially as we go through a phase of minimizing them)? They only need to memoize the edge to "potentially" benefit (as none of this memoizing is or ought to be required)
For all I know, memoizing should be an optional behavior, not a default one. Rerenders don't usually translate to UI changes. The fact that useSnakeCasedKeys
memorizes isn't required, just a provision to allow flows to opt-in when/if needed (as the alternative would mean "input" being memoized or not makes no difference).
useSignupStartEventProps
with useTracksEventProps
. Update tailored-ecommerce
flowcalypso_signup_start
. Update tailored-ecommerce
flow
…pdate tailored-ecommerce-flow cleanup
useSnakeCasedKeys
9c9a10f
to
ae77e60
Compare
This PR modifies the release build for the following Calypso Apps: For info about this notification, see here: PCYsg-OT6-p2
To test WordPress.com changes, run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like how the extra event properties are decided at a flow level, LGTM 👍
Thanks for taking the time! |
Part of addressing #94108
Proposed Changes
useSignupStartEventProps
to be replaced byuseTracksEventProps
, as per intended use to cover all signup framework events.STEPPER_TRACKS_EVENT_SIGNUP_START
useSnakeCasedKeys
to help pass props in their snake_cased form, allowing consuming end (flows) to work with camelCased variables.recordSubmitStep
for the additional-propsrecordTracksEvent
wrapper in Stepper that would do this instead. We can remove and not bother i.e. for the few rare cases where a flow needs to pass additional props, it can do it in snake_case form and so be it.DO NOT MERGE - depended on ongoing discussions in #94175
Why are these changes being made?
The
useSignupStartEventProps
prop/hook was defined for flows to extend the props recorded bycalypso_signup_start
. The newer hookuseTracksEventProps
was built to serve this need more generally (across all framework events, includingcalypso_signup_start
).Testing Instructions
calypso_signup_start
is recorded correctly forisSignupFlow
flowstailored-ecommerce
flow passes therecur
prop to thecalypso_signup_start
Tracks eventflow_variant
is passed correctly for any sub/child flow to thecalypso_signup_start
Tracks eventPre-merge Checklist