-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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
[POC] ownerState access: use context #35654
Conversation
@material-ui/unstyled: parsed: +0.34% , gzip: +0.37% |
I like this direction, the code looks much cleaner. Few thoughts:
Question:
|
Good point. But I think
In a perfect world, neither Joy nor Material UI would notice this change as it affects only the unstyled components, not hooks. But AFAIR we still have a couple of Joy components implemented based on components, so some changes will be necessary. One thing I realized is that it may not be necessary to include all of the owner props in the ownerState - just the calculated internal state, such as |
Sounds good 👍
Yes, we should be mindful of what's in here and make sure to memoize it. |
One interesting feature of this direction is that it allows the decoupling of the rendering of the slots from the parent. The slots can be rendered by userland. My main question is how will slots style themselves if
Should we care about this? From my perspective, since these are leaf components, they are meant to rerender. I would expect a memorization to waste CPU cycles overall. |
We still apply CSS classes that can be used for styling.
They aren't always leaf components. Compound components, such as Select render deeper trees inside slots, so in some cases preventing rerendering when unnecessary may save many CPU cycles. But for simple components you're right - there may be no gains. |
@michaldudak There are some, but not all the cases are covered by the class names. Say I want to change the background color on a lower element based on the
👍 to explore, I would be amazed if there are cases where it makes us one step ahead and not behind. |
I'd expect the But in general, yes, your point is valid - there could be cases where we don't expose everything as class names.
const StyledThumb = styled(WithSwitchState('span'))({ ownerState } => ` ... `);
EDIT: this doesn't seem to be possible. One way you could do this is: const Track = styled('span')(() => {
const { checked } = useSwitchUnstyledOwnerState();
return `
outline: 3px solid ${checked ? 'purple' : 'grey'};
`;
}); But it makes the style definition longer. |
Based on the use-cases we tried so far, this is what I could summirize:
So it boils down to what we want to optimize for. We shouldn't put all bet in styled components, because as the server components are going to become stable, I don't see a way for big growth, I feel like people will progressivly move to either static extraction styling soltuion, or different utility first classes frameworks, like Tailwind CSS. My ultimate question would be, could we support both and create guides that will teach developers what to so use based on their styling solution (maybe we can have a global provider for configuring the component about which paradigm to use (context vs prop propagation)). Then we can add a guide for how to use MUI Base with styled-components, utility first classes, plan CSS etc. |
Using CSS, SASS, Tailwind, and similar (basically anything other than styled components-like solutions) doesn't require using the IMO the use cases for the
One other advantage of a hook is simplified (and correct) types. If we had |
Nice, we are on the same page 👍
Agree 👍
Agree, I would say it would be a personal preference. So, if we weight these three groups, the third party components are the least usage (a guess would be 5%, maybe even less, correct me if you feel like this is wrong as it is truly just a guess). Considering that for 3. it's not clear what API is better, I would say maybe using the hook is a bit more the "React way of doing things" I would weight it a bit more than the |
👍 The remaining issue is the default value.
|
I think that the Here https://mui.com/material-ui/guides/routing/#global-theme-link we require to create a wrapper but it's only for global use with the theme.
As I understood hooks don't work with server components because the context doesn't: https://twitter.com/sebmarkbage/status/1587615484870098945.
With static extraction, Vanilla Extract API looks like this: https://github.com/timoclsn/mauli-vanilla-extract/blob/main/src/components/Button/Button.tsx#L49. Their API operates at the Since https://mui.com/material-ui/guides/routing/#link seems to work ok, It makes me wonder, how do we already solve this problem with Material UI? What would it take to reproduce the solution? |
Is it a problem, though? All of our unstyled components are client ones, as they are interactive, use state, effects, etc. (see the RFC for limitations of server components).
We don't expose the |
My thought was that maybe they don't all need to be. For some of them, it can make sense to be server-side only: an input element, in the footer, for a newsletter subscription can be server-side only. The same for the button that comes with it. A badge can be visual only too. But yeah, it won't make a huge difference at the end of the day 😁 |
This would require rewriting our components not to use effects or state, stripping them out of functionality. And if we take out functionality of an unstyled component, I don't think there will be any value left. I understand the value of server components is to provide data to the client, as they are closer to other servers and databases. Right now, I can't see the value of having UI controls as server components. |
@michaldudak OK, fair enough.
We could make useEffect a no-op and useState to return the default value.
I was considering the case where a design system is built with MUI Base, and mostly uses it for client-side, but where the developers still have a few basic use cases for them for server components. Effectively relying on the default behavior of an |
DO NOT MERGE
This is a playground that illustrates an alternative way of accessing
ownerState
in slot components.A SwitchUnstyled is used for this example.
Related issue: #32882
This is one of the possible solutions. The other one is described in #35668.
A new hook,
useSwitchUnstyledOwnerState
is introduced. It can be used within slot components to get the state of the owner component and affect what's being rendered.In this example, a different emoji is displayed depending on the state of the Switch.
Advantages over the existing API:
ownerState
prop and may forward everything they receive.ownerState
should not be placed on a DOM element as it's not a valid attribute (and React rightfully complains about this).ownerState
.ownerState
s from different "layers" (i.e., Base and Joy components) won't be an issue anymore. Each ownerState will be in a different context and will be able to be accessed independently. Also this will eliminate the problems withownerState
types we currently have when using Base components as slots in other Base components.Disadvantages:
const { ownerState } = props;
thanconst ownerState = useSwitchUnstyledOwnerState();
. It won't be possible to use a shorthand notation to define a simple component:Playgrounds
New API: https://codesandbox.io/s/sharp-booth-hx3xtn?file=/src/App.tsx
Existing API: https://codesandbox.io/s/confident-hermann-q1kiwf?file=/src/App.tsx