【问题标题】:How best to create custom styled components in MUI如何最好地在 MUI 中创建自定义样式的组件
【发布时间】:2021-12-21 13:35:43
【问题描述】:

看似简单的问题:

  1. 示例背景:我们有许多项目列表,并使用<List> 在 UI 中呈现它们。
  2. 示例问题:我们通常(但并非总是)想要删除在<List> 上注入的额外填充(例如:<UnpaddedList>)。

作为另一个例子,也许我们希望大多数列表在默认情况下是可折叠的,使用<List onClick={...}> 触发器变成<CollapsableList>。对于下面的大多数示例,未填充的就足以说明。

乍一看,我预计会出现CustomList extends List (but see Facebook inheritance advice) 之类的东西。有很多方法可以做到,但是优点/缺点是什么……它们似乎相互冲突:

createStyled()

这是为了完全取代主题......有时会打破品牌标准。虽然我们可以返回并合并现有的主题,但这似乎违背了这个工具的目的,deepmerge 可能会降低性能?如果它可以继承当前的主题上下文,这将很有效。也许很多额外的组件名称是不好的做法?例如:ListUnpaddedListUnpaddedLargeListUnpaddedLargeGreenList

https://mui.com/system/styled/#create-custom-styled-utility

createTheme()

这允许完全覆盖每个组件的样式和道具。唯一的问题是可能不清楚为什么组件以某种方式设置样式并保留其名称。 (例如:<List> 未重命名为 <UnpaddedList>)如果您有一个组件从树中某处的父组件继承主题并以意想不到的样式出现,这可能会令人困惑。开发人员必须跟踪每个父组件以找到主题注入<ThemeProvider> 的位置。但也许这种以意想不到的方式注入子主题将是它自己的反模式。

此外,在没有明确的文档/打字稿的情况下,需要大量阅读才能确定如何最好地传递和修改当前主题:

function extendThemeWithGreen(theme: Theme) {
  let themeOptions: ThemeOptions = { palette: { primary: { main: "green" } } };
  return createTheme(theme, themeOptions);
}

function Example() {
  return <ThemeProvider theme={extendThemeWithGreen}> example</ThemeProvider>;
}

另一个问题是some components have arbitrary white-space injected 进入他们。这没有记录,也没有类型提示。发现这些的唯一方法是寻找源代码。从那里您可能必须创建另一组样式来覆盖原生样式并将膨胀引入应用程序。

https://mui.com/system/styled/#custom-componentshttps://mui.com/customization/how-to-customize/#2-reusable-style-overrides

return &lt;List {...props} /&gt;

包装组件会很好。 (例如:const UnpaddedList = (props) =&gt; &lt;List disablePadding {...props} /&gt;;) 到目前为止,这已经很麻烦了。例如,道具应该是ListProps 还是OverridableComponent&lt;ListTypeMap&lt;{}, "ul"&gt;&gt;?或者假设最终组件和包装组件都有sx...我是否必须设置deepMerge 来处理重复的道具。也许我只是需要花更多的时间来完成它?

https://mui.com/guides/composition/#wrapping-components

sx={...}style={...}class=...

这些道具通常允许自定义,但它们实际上是一次性的。例如:您还必须&lt;List style={{padding:0}} /&gt;,这会失去类型安全(预计将来会发生问题) class 可以分开,但仍然很难保持类型安全。旧版makeStyles( 类似

https://mui.com/system/the-sx-prop/https://mui.com/styles/api/#createstyles-styles-styles

&lt;UnstyledList component={...}

这主要是即将推出的功能,尚未完全实施。虽然这可以避免未来的 css 冲突,但它仍然不利于 props 覆盖(或者如果它确实......从文档中不清楚)

https://mui.com/customization/unstyled-components/#main-content

&lt;Box component={List} ... /&gt;

使用Box 包装器创建自定义组件。文档对此并不完全清楚。可能是这样的:

function UnpaddedList(props: ListProps){
  return <Box component={List} disablePadding {...props} />
}

许多组件 props 都有通用修饰符...但是不清楚如何编写这个新组件以匹配(或扩展)原始组件 props

https://mui.com/system/box/#overriding-mui-components

variant="unpadded"

这很接近,但它似乎会造成打字问题或特殊处理导入。我可以看到这会在路上造成混乱,但如果没有正确实施,至少 linting 会发出警告。它没有很好的组合方式。对于没有内置变体的组件,如何做到这一点也不清楚。

https://mui.com/customization/theme-components/#adding-new-component-variants

props

当然,有些,但不是全部,可以通过 props 来保持类型安全。 (例如:&lt;List disablePadding={true}&gt;)但是这个isn't DRY。总体上管理起来更糟糕(没有品牌标准)。它还使代码更难阅读并且过于冗长

其他方法?

也许我错过了另一种方式。我也找不到 MUI 组件中hardcoded whitespace 的任何优雅解决方案

【问题讨论】:

    标签: reactjs material-ui


    【解决方案1】:

    如果您有一个在多个地方使用的组件,并且其中只有一个需要具有一些特殊样式,或者您需要调整或修复特定布局中的边缘情况,请使用sx prop。它适用于这样的一次性样式:

    <List sx={{ p: 0 }}>
    

    如果您需要偶尔在组件中应用一些样式,请使用styled。例如,如果一个组件在 100 个地方使用但仅在 20 个地方使用,则需要禁用填充,然后添加一个填充道具以在极少数情况下启用样式:

    const options = {
      shouldForwardProp: (prop) => prop !== 'disablePadding',
    };
    const List = styled(
      MuiList,
      options,
    )(({ theme, disablePadding = false }) => ({
      ...(disablePadding && {
        padding: 0,
      }),
    }));
    
    // I dont always use disablePadding but sometimes I need it
    <List disablePadding>
    

    【讨论】:

    • 我真的很喜欢你建议的 styled(...shouldForwardProp 方法。我会试一试。不知何故,我忽略了styled(...,即使经过几个小时的查找,即使我确实看到了createStyled(...。一旦我有时间测试它,我会标记为答案。谢谢!对于其他人来说,这是链接:mui.com/system/styled/…
    • 在我最初的测试中,这似乎只会影响样式(不会影响功能)。因此,例如,如果我想做&lt;List maxItems={10}&gt;,那么能够接收道具会很好,然后在将孩子传递给标准List 组件之前拥有children = children.slice(0,10) 之类的东西。不幸的是,styled 方法似乎无法做到这一点
    • @bristweb styled 仅用于创建样式表 (CSS)。 children.slice(0,10) 是删除某些项目的 JS 代码。你的那个具体例子是关于组件逻辑而不是样式,所以你不能使用 styled 来完成那个任务。您可以创建MuiList 的包装器组件并轻松删除多余的子组件。
    猜你喜欢
    • 2022-01-08
    • 1970-01-01
    • 2019-11-17
    • 2021-12-22
    • 1970-01-01
    • 2019-03-03
    • 1970-01-01
    • 2021-12-12
    • 1970-01-01
    相关资源
    最近更新 更多