Material-ui: [withStyles] 添加从样式对象中获取组件的 props 的能力

创建于 2017-08-02  ·  39评论  ·  资料来源: mui-org/material-ui

描述

使用createStyleSheet ,没有办法(至少我知道)访问组件的道具。 我认为这很重要,因为有时需要将尺寸、网址图像和其他样式作为道具传递给组件。

今天唯一的解决方案是将这些东西分成内联样式,但据我所知,material-ui v1 使用jssreact-jss ,这两个已经给了你可能性通过接收道具然后返回所需样式的函数访问道具,如下所示:

const styles = {
  button: {
    background: props => props.color
  },
  root: {
    backgroundImage: props => `url(${props.backgroundImage})`
  }
}

// Reference: https://github.com/cssinjs/react-jss#example

你如何看待在 material-ui 上实现类似的东西?

enhancement important

最有用的评论

我在v1.x 里程碑中添加了这个问题。 很多人都在要求它。 我们很快就会得到它。

capture d ecran 2018-07-29 a 13 12 03

所有39条评论

react-jss 实现了该功能。 您始终可以在我们的造型解决方案上使用它。 在这里实现该功能的真正动机应该是围绕组件的更简单/更好的内部实现。

react-jss injectStyles() 也这样做,但似乎最好将道具添加到StyleRuleCallback

const styles = (props, theme) => ({})
这样你就不仅限于依赖于 props 的值。

@Shamplol 的反馈让我觉得我们可以利用这个新功能来允许用户为我们的组件提供自定义的color ,而不是预定义的。 CSS 大小影响尚不清楚,但它会使组件颜色覆盖更简单。 这是有待调查的。 然后,一旦 css 变量浏览器支持足够高(从现在起 2 年?),我们就可以依赖它。

@oliviertassinari在某些情况下实际上不会减少 css 大小吗?
据我所知,我们目前为...Primary...Accent定义了所有类 - 这种变化是否意味着我们只需要维护...Colorized ? 或者你担心生成的css?

无论哪种方式,我认为这都会极大地改善 dx,因为我们必须基本上重新实现像https://github.com/callemall/material-ui/blob/v1-beta/src/Button/Button.js#L11这样的复杂类。想使用非调色板颜色。

在某些情况下,css 大小实际上不会减少吗?

@sakulstra很难说。 这将取决于实施。 也许 :)。

从 TypeScript 类型的角度来看,如果 _both_ propstheme可以在样式规范中以这种方式访问​​,那就太好了:

const styles = {
  button: {
    background: ({ theme }) => theme.palette.primary[200]
  },
  root: {
    backgroundImage: ({ props }) => `url(${props.backgroundImage})`
  }
};

原因是 TypeScript 在传递函数对象时经常无法为withStyles推断正确的类型,因此您必须提供额外的类型注释才能使其工作,例如

withStyles<'button' | 'root'>(theme => ...)

如果 props 也传入,这将变成

withStyles<'button' | 'root', Props>((theme, props) => ...)

这件事的现状如何? 有这个功能真是太好了

@lucasmafra我已将此功能添加到 v1 版本发布里程碑中。 我们越早发布 v1 越好。

此功能是能够编写结合道具、媒体查询和交互状态的表达风格规则的关键。 您不能用内联样式替换该功能。 不幸的是, withStyles在我的任何项目中都无法使用,直到它被添加。

你总是可以设置一个自定义主题,并使用这个约定:我们真的很喜欢样式组件如何让你通过在 MuiThemeProvider 中嵌套 ThemeProvider 来访问 props.theme 开箱即用,当两者都调用 theme={theme} 时。 它扩展了 mui 公开的默认主题

//inline with HOC Method
 h1 style= {{ 'color: this.props.theme.palette.primary[500]' }}

//styled components ( no method necessary )
const Heading = styled.h1`
  color: ${p => p.theme.palette.primary['500']};
`

我只需要使用函数值,所以我使用了 react-jss 的injectSheet()函数。 我习惯用Mui的withStyles()函数,那么用injectSheet代替withStyles有什么缺点吗?

@damien-monni 您无法访问您的 MUI 主题。

大家好,只是想分享我的 Material-UI样式组件类API 版本。 它没有经过“大量”测试,但似乎运行良好并提供:

  • propstheme提升到样式函数。
  • 将自定义props传递给包装的组件
  • 通过React.forwardRef转发引用
    (编辑:Refs 目前仅适用于 html 标签,而不是大多数基本的 Material-UI 组件,这需要内部支持。当我有时间时可能会在 PR 上工作,需要接受functionobject prop-types,并检查无状态组件是否传递给子组件)

相关问题:#10825、#7633

styled.js

import React, { Component } from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';

function styled(WrappedComponent, customProps) {
  return (style, options) => {
    class StyledComponent extends Component {
      render() {
        let {
          forwardRef,
          classes,
          className,
          ...passThroughProps
        } = this.props;
        return (
          <WrappedComponent
            ref={forwardRef}
            className={classNames(classes.root, className)}
            {...passThroughProps}
            {...customProps}
          />
        );
      }
    }

    StyledComponent.propTypes = {
      classes: PropTypes.object.isRequired,
      className: PropTypes.string,
    };

    let hoistedProps = {};

    const styles =
      typeof style === 'function'
        ? theme => {
            return { root: style({ ...theme, theme, props: hoistedProps }) };
          }
        : { root: style };

    const WithRef = withStyles(styles, options)(StyledComponent);

    return React.forwardRef((props, ref) => {
      hoistedProps = props;
      return <WithRef {...props} forwardRef={ref} />;
    });
  };
}

export default styled;

示例使用

const MobileNav = styled('nav')(({ theme, props }) => ({
  '&.pos-fixed': {
    top: 0,
    position: props.fixed ? 'fixed' : 'absolute',
    zIndex: 99,
    animation: 'fadeInDown 0.3s ease-out forwards',
    backgroundColor: theme.palette.common.white,
  },
}));

带自定义道具

const StyledButton = styled(Button, { component: Link })(
  ({ theme, props }) => ({
    color: props.disabled ? 'gray' : 'blue',
    [theme.breakpoints.down('sm')]: {
      color: 'red',
    },
  })
);

@oliviertassinari为了解决这个问题,我使用了以下解决方案:

    componentWillMount() {
        const {color} = this.props;
        jss.setup(jssPreset());
        const stylesheet = jss.createStyleSheet({
            underline: {
              "&:after": {
                backgroundColor: `${color} !important`
              }
            }
        }).attach();
        this.underlineClass = stylesheet.classes.underline;
    }

它工作得很好,但是否有一些我没有看到的潜在问题? 我不喜欢我必须调用 jss.setup 两次,例如😅。 我不确定我是否理解jss生命周期。 我很惊讶我需要在这里调用setup()

它工作得很好,但是否有一些我没有看到的潜在问题?

@wcandillon我可以看到一些潜在的问题: 1. 每次安装组件的实例时,您都会注入新的类名。 2. 您将无法在服务器端呈现您的组件。 3. 你不会得到正确的 CSS 覆盖注入顺序。

我开发了这个库来拥有风格的道具:

https://github.com/JacquesBonet/jss-material-ui

在一个项目上测试成功。

起初,我使用 danielmahon 解决方案,但遇到了样式继承问题。

@oliviertassinari我们现在有创建动态 css/动画的替代方法吗? 谢谢 :)

@HunderlineK一些替代方案: https : //material-ui.com/customization/overrides/#2 -dynamic -variation-for-a-one-time-situation。

@danielmahon您的方法正是我现在正在寻找的方法来解决我的问题,尽管“样式组件”在收到新道具时不会重新渲染。 你有没有试过别的?

我会想一些不同的,如果我想出什么我会让你知道

💰 刚刚给那个人附加了 50 美元的赏金 :)

https://www.bountysource.com/issues/47838203-withstyles-add-the-ability-to-get-the-component-s-props-from-within-the-style-object

就像@lewisdiamond所说的那样, const styles = (props, theme) => ({})会非常整洁。

或者const styles = (theme, props) => ({})可能是不间断的。

我在v1.x 里程碑中添加了这个问题。 很多人都在要求它。 我们很快就会得到它。

capture d ecran 2018-07-29 a 13 12 03

@oliviertassinari这可能对withStyles的输入有重大影响,请告诉我是否可以提供帮助

@pelotom谢谢,我会告诉你的。 我希望我这个月可以开始研究这个问题。

是否正在进行这方面的工作? 这是 IMO 的一个关键功能,也许我可以提供帮助。

编辑:我开始研究它。 设法将道具传递给withStyles接受的styles函数,唯一的问题是道具更改时不会更新样式。 解决后将创建一个 PR。

嗨,我刚刚遇到一个用例,我需要它来自定义头像组件的颜色,除此之外没有其他方法可以控制组件的所有变体的样式。

const styles = theme => ({
  chip:{
  },
  separator: {
    marginRight: theme.spacing.unit,
  },
  fright: {
    float: 'right',
  },
  fleft: {
    float: 'left',
  },
  outlinedPrimary:{
    color: props =>  stringToColor( props.username),
    border: props => `1px solid ${fade(stringToColor(props.username), 0.5)}`,
    '$clickable&:hover, $clickable&:focus, $deletable&:focus': props => ({
      backgroundColor: fade(stringToColor(props.username), theme.palette.action.hoverOpacity),
      border: `1px solid ${stringToColor(props.username)}`,
      }),
  },
  outlined: {
    backgroundColor: 'transparent',
    border: props => `1px solid ${
      theme.palette.type === 'light' ? stringToColor(props.username) : fade(stringToColor(props.username))
    }`,
    '$clickable&:hover, $clickable&:focus, $deletable&:focus': props => ({
      backgroundColor: fade(stringToColor(props.username), theme.palette.action.hoverOpacity),
      }),
    },
});

您可以查看我的解决方案 Japrogramer: https :

谢谢,我去看看。

我今天早些时候需要这个功能所以我写了一个 HOC。 withStyles自己做了一些缓存,所以我真的不能说这有多大影响,但我会在空闲时间看看withStyles的缓存实现,现在任何人都在寻找一个快速获得道具和主题的方法就可以玩得很开心

警告

如果道具更改与样式表类的索引号更改或 withStyles HOC 中的某些内容有关,则此组件将完全重新安装

import React from 'react';
import { withStyles } from '@material-ui/core/styles';

const { createElement, forwardRef } = React

const withPropsStyles = ( style ) => {

    const withPropsStyles = ( component ) => {

        return forwardRef( (props, ref) => {

            const proxy = (theme) => style(props, theme)

            const hoc = withStyles(proxy)(component)

            return props.children ? 
                createElement(hoc, { ...props, ref}, props.children) :
                createElement(hoc, {...props, ref}) 
        }) 
    }

    return withPropsStyles
}

export default withPropsStyles

示例使用

const styles = (props, theme) => ({
    root:{
        backgroundColor: props.light ? theme.palette.primary.light : theme.palette.primary.main 
    },
})

const SomeComponent = ({classes}) => <div className={classes.root}/>

export default withPropsStyles(styles)(SomeComponent)

结论

简单且有效(但也需要重新安装全部费用)

有了这个变化,我们可以从库中删除内联样式的使用,以支持 100% JSS 吗? 我的应用程序不适用于内联样式,当我用 JSS 替换涟漪效果时,我意识到我需要这个功能。 也许对性能的影响很小,但看起来更干净。

@koshea 放弃内联样式。 我也真的不喜欢内联样式,它应该可以很好地替代withStyles作为装饰器或示例中的替代品。

我还想提一下,使用内联样式不允许启用强大的内容安全策略。
它需要向样式指令添加unsafe-inline标志,这是不安全的。

支持 props 的动态样式应该可以解决这个问题

大家好,很抱歉“就这样”加入讨论。 我最近开始使用 Mui(使用 Typescript),虽然我发现它是一个非常强大的库,但它确实有其复杂性。

我在上面的一些评论中注意到,对于这个功能应该是(props, theme) => {}还是(theme, props) => {} 。 我想强调@pelotom所说的关于在他的评论中创建propstheme命名属性的内容。 一旦这种变化发生(我真的很期待),这样做可能会让我们更容易重构样式定义。 干杯🙂

谢谢大家的耐心! #13503 正在处理这个问题。 这是我们想要实现的组件助手的要求。 我们也开始试验钩子 API: https :

这使它成为4.0吗? 看起来makeStyles回调没有props参数。

@city41 const classes = useStyles(props);

我知道了。 所以看起来是这样

const useStyles = makeStyles(theme => {
    return {
        foo: {
            color: theme.props.danger ? '#ff0000' : '#00ff00'
        }
    };
});

function MyComponent(props) {
    const classes = useStyles(props);

    return <div className={classes.foo}>...</div>;
}

我在网站的样式 API 部分中没有看到这一点。 看看能不能发个PR

@city41 https://material-ui.com/styles/basics/#adapting -based -on-props 中有一个文档的开头。

很酷,很高兴看到文档得到更新。 对于遇到此问题的其他人,这是我如何结合主题和道具来设计组件的样式

import React from 'react';
import { Button, Theme, makeStyles } from '@material-ui/core';

interface ButtonProps {
    destructive: boolean;
}

const useButtonStyles = makeStyles<Theme, ButtonProps>(theme => {
    return {
        root: props => ({
            backgroundColor: props.destructive ? theme.palette.error.main : theme.palette.primary.main
        })
    };
});

export const PrimaryButton: React.FunctionComponent<ButtonProps> = props => {
    const classes = useButtonStyles(props);

    return <Button {...props} className={classes.root} variant="contained" />;
};

如何在外部样式 json 文件中使用 prop?

例如这是外部文件

const typographyStyle = {
  title2: {
    fontFamily:"Montserrat",
    fontStyle:"normal",
    fontWeight:"800",
    fontSize:"72px",
    lineHeight:"88px",
    letterSpacing:"-0.02em",
    // color:"#304C82"
    color : props => {
      console.log(props,'c1');
      return props.color
    }

  }
};

export default typographyStyle;

我导入这个文件并传播对象

import typographyStyle from "../assets/jss/material-kit-pro-react/views/componentsSections/typographyStyle";


const styles = theme =>  ({
    ...typographyStyle,
    homeSearch:{
        width: '100%',
        '& div':{
            '& input':{
                "color":"#304C82",
                height: 65,
                fontFamily: 'Open Sans',
                fontStyle: 'normal',
                fontWeight: 800,
                fontSize: '48px',
                lineHeight: '65px',
                letterSpacing: '-0.03em',
                '&::placeholder':{
                    fontFamily: 'Open Sans',
                    fontStyle: 'normal',
                    fontWeight: 800,
                    fontSize: '48px',
                    lineHeight: '65px',
                    letterSpacing: '-0.03em',
                    color: '#EAEAEA'
                }
            }
        }
    },

  });

现在在颜色函数上我得到 props = {} 。

有人可以在这方面帮助我吗?

更新:

似乎我做错了什么,因为即使在我的主 style.js 文件中我也得到了空对象

    homeSearch: props => {
        console.log(props);
        return {
        width: '100%',
        border:  `1px solid ${props.color}`
        ,
        '& div':{
            '& input':{
                "color":"#304C82",
                height: 65,
                fontFamily: 'Open Sans',
                fontStyle: 'normal',
                fontWeight: 800,
                fontSize: '48px',
                lineHeight: '65px',
                letterSpacing: '-0.03em',
                '&::placeholder':{
                    fontFamily: 'Open Sans',
                    fontStyle: 'normal',
                    fontWeight: 800,
                    fontSize: '48px',
                    lineHeight: '65px',
                    letterSpacing: '-0.03em',
                    color: '#EAEAEA'
                }
            }
        }
    }
},
此页面是否有帮助?
0 / 5 - 0 等级

相关问题

anthony-dandrea picture anthony-dandrea  ·  3评论

rbozan picture rbozan  ·  3评论

chris-hinds picture chris-hinds  ·  3评论

ryanflorence picture ryanflorence  ·  3评论

ericraffin picture ericraffin  ·  3评论