Skip to content
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

[system] Fix unnecessary styles created from sx #33752

Merged
merged 7 commits into from Aug 8, 2022

Conversation

siriwatknp
Copy link
Member

@siriwatknp siriwatknp commented Aug 2, 2022

Issue

https://codesandbox.io/s/cool-mopsa-tvv9gp?file=/demo.tsx

When styled-components are recreated more than once, the styles from sx are always generated everytime:

const Child = styled("div")({});

const Parent = styled(Child)({});

<Parent sx={{ color: 'orange' }}>Color</Parent>

Screen Shot 2565-08-02 at 14 07 43

How does it happen?

Every time, the component is wrapped with styled we attach a function that watches the sx prop and transforms it into styles. Meaning, that if the component is wrapped 3 times, 3 similar functions are created and are called when the component is rendered.

Why we haven't noticed it?

This is because we don't have multiple compositions using styled in Material UI components. However, Joy is using this pattern to reduce complexity and reuses styles, so that's when I noticed the issue.

The fix

Using a similar technique as emotion, the lastest styled component will call the function to skip the sx function in the nested styled component. (This introduces another bug)

The actual fix would be to read the styles attached by emotion/style-components and filter the sx from the child component so that the sx apply only on the latest composite component.

This is a minimal implementation that demonstrate the fix with style-components. https://codesandbox.io/s/styled-components-demo-forked-nzchg0?file=/src/App.js

Tests added.


@siriwatknp siriwatknp added the package: system Specific to @mui/system label Aug 2, 2022
@siriwatknp siriwatknp requested review from mnajdova and hbjORbj and removed request for mnajdova August 2, 2022 07:15
@mui-bot
Copy link

mui-bot commented Aug 2, 2022

Details of bundle changes

Generated by 🚫 dangerJS against c2e1071

@michaldudak
Copy link
Member

There was a similar issue reported by a community member recently: #33443. I suppose this PR fixes it as well, doesn't it?

@siriwatknp
Copy link
Member Author

There was a similar issue reported by a community member recently: #33443. I suppose this PR fixes it as well, doesn't it?

Nope, it is a different issue but I propose the fix in #33443 (comment). Please take a look.

return (tag, inputOptions = {}) => {
/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try to put all emotion/styled-component related logic in the styled-engine packages. Is it possible to move this there, or maybe just export the path to the style rules from the adapter packages? Something like:

// this will be set to `__emotion_styles` & `componentStyle.rules` respectivly
import { styleRulesPath } from '@mui/styled-engine';

const styleRules = getValue(tag, styleRulesPath);
if(styleRules) {
// other logic
}

This way we won't have anything specific in the system related to emotion/styled-components.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Member

@mnajdova mnajdova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would happen if the sx prop is provided as an array of styles?

@siriwatknp
Copy link
Member Author

siriwatknp commented Aug 5, 2022

What would happen if the sx prop is provided as an array of styles?

That's fine because the sx prop is wrapped in a function. The logic just filters out the systemSx of the composite component, it does not involve with the value of the sx prop.

// It is this function that will be filtered out, the `sx` prop is not related to the logic (not calculated because the filter logic is done before the component render
const systemSx = (props) => {
  const theme = isEmpty(props.theme) ? defaultTheme : props.theme;
  return styleFunctionSx({ ...props, theme }); // `sx` is in the props
};

@propG
Copy link

propG commented Aug 5, 2022 via email

/**
* For internal usage in `@mui/system` package
*/
export function processStyles(tag: React.ElementType, processor: (styles: any) => any): void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add some prefix (internal_ or unstable_)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point.

Copy link
Member

@mnajdova mnajdova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, please resolve just the one comment that I added.

@siriwatknp siriwatknp merged commit e430fbb into mui:master Aug 8, 2022
daniel-rabe pushed a commit to daniel-rabe/material-ui that referenced this pull request Nov 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: system Specific to @mui/system
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants