-
Notifications
You must be signed in to change notification settings - Fork 592
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
fix(Button): memoize call to merge.all #2252
Conversation
🦋 Changeset detectedLatest commit: 9506801 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
size-limit report 📦
|
Definitely an improvement! Would be helpful to run the same or similar benchmarks from https://github.com/github/primer/issues/1191 (without any data) I wonder if we'll get a lot of benefit from cache hits in memo when if it includes user provided Alternative solution: How do you feel about inserting css for all variants on render and using then a data-attribute to set the style. This would remove the function calls for rendered to something like <button className="btn-h4sh" data-variant="primary" data-size="small"/>
// css:
.btn-h4sh {
// common and default styles
}
.btn-h4sh[data-variant=primary] {
// primary styles
} We use data-attributes for styling in some other places like ButtonCounter and ActionList divider |
Thanks so much @siddharthkp!
Great point, I moved it out of
Sounds great, in order to profile would you recommend pulling down their project / npm link'ing primer and running the same trace?
Happy to do it, would that be what you'd recommend? |
cc @pksjce if you have any recommendations for setting a baseline here and profiling different approaches! |
@pksjce definitely! I'll use that for some quick ad-hoc measurements locally to see what you all think 👀 ScenariosBaseline
useMemo (sxProp in dep array) Codeconst ButtonBase = forwardRef<HTMLElement, ButtonProps>(
({children, as: Component = 'button', sx: sxProp, ...props}, forwardedRef): JSX.Element => {
const {leadingIcon: LeadingIcon, trailingIcon: TrailingIcon, variant = 'default', size = 'medium'} = props
const {theme} = useTheme()
const iconWrapStyles = {
display: 'inline-block'
}
const sxStyles = useMemo(() => {
return merge.all([
getButtonStyles(theme),
getSizeStyles(size, variant, false),
getVariantStyles(variant, theme),
(sxProp || {}) as SxProp
])
}, [theme, size, variant, sxProp])
return (
<StyledButton as={Component} sx={sxStyles} {...props} ref={forwardedRef}> useMemo (merge at sx call site) Code const sxStyles = useMemo(() => {
return merge.all([getButtonStyles(theme), getSizeStyles(size, variant, false), getVariantStyles(variant, theme)])
}, [theme, size, variant])
return (
<StyledButton as={Component} sx={merge(sxStyles, sxProp as SxProp)} {...props} ref={forwardedRef}> Summary
Include
|
Thanks for that analysis! Yes, so as I understand we want to memoize the internal style calculations and merge the user styles at the call site.
Fixing these two issues would fundamentally improve perf of |
Reference: https://github.com/github/primer/issues/1191
This PR updates
ButtonBase
to memoize the call tomerge.all
withuseMemo
. This seemed like the best next step when I was taking a look at the issue, let me know if I misunderstood the approach!A quick aside, I removed the default value of
sx
so thatuseMemo
wouldn't be called each render. The fallback value has been moved to themerge.all
callMerge checklist