如何在 makeStyles 中使用“主题”和“道具”?

Posted

技术标签:

【中文标题】如何在 makeStyles 中使用“主题”和“道具”?【英文标题】:How to use 'theme' and 'props' in makeStyles? 【发布时间】:2019-09-30 08:26:47 【问题描述】:

如何编写makeStyles() 以便它允许我同时使用主题变量和道具?

我试过了:

const useStyles = makeStyles(theme => (
  appbar: props => (
    boxShadow: "none",
    background: "transparent",
    marginTop: theme.spacing(2),
    marginBottom: theme.spacing(2),
    color: theme.palette.getContrastText(props)
  ),
));

并在组件中调用它:

const classes = useStyles(backgroundColor);

其中backgroundColorCSSProperties["backgroundColor"] 类型的组件上的道具

但我得到了错误:

TypeError: Cannot read property 'rules' of undefined
    at RuleList.onUpdate (C:\Users\...\node_modules\jss\dist\jss.cjs.js:944:14)
    at RuleList.update (C:\Users\...\node_modules\jss\dist\jss.cjs.js:923:12)
    at StyleSheet.update (C:\Users\...\node_modules\jss\dist\jss.cjs.js:1178:39)
    at attach (C:\Users\...\node_modules\@material-ui\styles\makeStyles\makeStyles.js:141:18)
    at C:\Users\...\node_modules\@material-ui\styles\makeStyles\makeStyles.js:262:7
    at useSynchronousEffect (C:\Users\...\node_modules\@material-ui\styles\makeStyles\makeStyles.js:207:14)
    at C:\Users\...\node_modules\@material-ui\styles\makeStyles\makeStyles.js:254:5
    at Layout (C:\Users\...\.next\server\static\development\pages\index.js:1698:17)
    at processChild (C:\Users\...\node_modules\react-dom\cjs\react-dom-server.node.development.js:2888:14)
    at resolve (C:\Users\...\node_modules\react-dom\cjs\react-dom-server.node.development.js:2812:5)
    at ReactDOMServerRenderer.render (C:\Users\...\node_modules\react-dom\cjs\react-dom-server.node.development.js:3202:22)
    at ReactDOMServerRenderer.read (C:\Users\...\node_modules\react-dom\cjs\react-dom-server.node.development.js:3161:29)
    at renderToString (C:\Users\...\node_modules\react-dom\cjs\react-dom-server.node.development.js:3646:27)
    at render (C:\Users\...\node_modules\next-server\dist\server\render.js:86:16)
    at renderPage (C:\Users\...\node_modules\next-server\dist\server\render.js:211:20)
    at ctx.renderPage (C:\Users\...\.next\server\static\development\pages\_document.js:2404:22)

  100 |   handleSignUpClick,
  101 |   backgroundColor
  102 | ) => 
> 103 |   const classes = useStyles(backgroundColor);
  104 |   return (
  105 |     <AppBar className=classes.appbar>
  106 |       <Container maxWidth="lg">

编辑:我使用的是 4.0.0-beta.1 版本的材料核心和样式

【问题讨论】:

我可能会迟到。但是,有一个非常酷的视频,它会引导您了解将主题传递给 makeStyles 的基础知识:youtu.be/… 如果您使用的是 MUI v5,请参阅this 答案以了解替代方法。 【参考方案1】:

你可以这样做:

import  makeStyles, createStyles, Theme  from "@material-ui/core/styles";

...
...

const classes = useStyles();

...
...

const useStyles = makeStyles((theme: Theme) =>
  createStyles(
    root: propName => (
      border: "none",
      boxShadow: "none",
      cursor: propName ? "pointer" : "auto",
      width: "100%",
      backgroundColor: "#fff",
      padding: "15px 15px"
    ),

    updated: 
      marginTop: 12,
      fontWeight: 400,
      color: "#939393"
    
  )
);

您可以在要设置样式的元素中使用道具名称,方法是将其设置为返回样式的箭头函数。此外,您还可以在 createStyles 钩子中设置其他元素的样式。这花了我一些时间,我希望任何人都觉得它有用。 ✨?

【讨论】:

【参考方案2】:

测试:

"@material-ui/core": "^4.0.0-beta.1",
"@material-ui/styles": "^4.0.0-rc.0",

javascript 示例:

我的组件.js

import React from 'react';
import  makeStyles  from '@material-ui/styles';

import  useStyles  from './my-component.styles.js'; 

const myComponent = (props) => 
    const styleProps =  width: '100px', height: '100px' ;
    const classes = useStyles(styleProps);

    return (
        <div className=classes.mySelector></div> // with 100px and height 100px will be applied
    )

我的组件.styles.js

export const useStyles = makeStyles(theme => (
    mySelector: props => (
        display: 'block',
        width: props.width,
        height: props.height,
    ),
));

TypeScript 示例:

我的组件.ts

import React,  FC  from 'react'; 
import  makeStyles  from '@material-ui/styles';

import  useStyles  from './my-component.styles.ts'; 
import  MyComponentProps, StylesProps  from './my-component.interfaces.ts'; 

const myComponent: FC<MyComponentProps> = (props) => 
    const styleProps: StylesProps =  width: '100px', height: '100px' ;
    const classes = useStyles(styleProps);

    return (
        <div className=classes.mySelector></div> // with 100px and height 100px will be applied
    )

我的组件.interfaces.ts

export interface StyleProps 
    width: string;
    height: string;


export interface MyComponentProps 

我的组件.styles.ts

import  Theme  from '@material-ui/core';
import  makeStyles  from '@material-ui/styles';

import  StyleProps  from './my-components.interfaces.ts';

export const useStyles = makeStyles<Theme, StyleProps>((theme: Theme) => (
    mySelector: props => ( // props =  width: string; height: string 
        display: 'block',
        width: props.width,
        height: props.height,
    ),
));

更新

重新测试

"@material-ui/core": "^4.12.X"

【讨论】:

@SaadKhan,你能告诉我你用的是哪个版本的@material-ui吗?我想更新 Tested with part。 "@material-ui/core": "^4.8.3" 希望对您有所帮助 完全帮助我。谢谢! M-UI:4.12.x【参考方案3】:

这是一个示例,说明如何在 makeStyles() 中仅使用 props 或 props 和主题,就像 styled-components 一样

component.js

import  tableCellStyling  from './component.styled.js';

const RenderRow = (props) => 
    const  noPaddingTopBottom  = tableCellStyling(props);
    return(
        <StyledTableRow>
            data.map( (row,i) => (
                <StyledTableCell className=noPaddingTopBottom>
                    row.data
                </StyledTableCell>
            )
        </StyledTableRow>
    )
;

假设我的由 RenderRow 组件传递给 tableCellStyling 的 props 对象中有 color: 'grey', thinRow: true

component.styled.js

import  makeStyles  from '@material-ui/core/styles';

export const tableCellStyling = makeStyles(theme => (
    noPaddingTopBottom: 
        borderBottom: ( color ) => color ? `2px solid $color` : '2px solid red',
        paddingBottom: props => props.hasActions && 0,
        paddingTop: props => props.hasActions && 0,
        backgroundColor: theme.palette.common.white,
    ,
));

【讨论】:

【参考方案4】:

我们一般有 2 种模式,你的 prop 变量是否被导入到组件中。

    如果你的prop变量是导入的,是全局变量,所以在makeStyles()中有效:
     import prop from ...
    
     const useStyles = makeStyles((theme) => (
       className:
          // use prop
       
     )
    
     define component...
    如果您的 prop 变量在组件中定义(例如状态),您有 2 个选择:​​i>
您可以将 prop 变量传递给 makeStyles():

    const useStyles = makeStyles((theme,prop) => (
      className:
         // use prop
      
    )
    
    define component...
您可以在不向 makeStyles() 传递任何参数(主题除外)的情况下使用箭头函数:
    const useStyles = makeStyles((theme) => (
      className:(prop)=>(
         //use prop
      )
    )

    define component...

【讨论】:

【参考方案5】:

您可以这样做:(我不知道是否是最好的方法,但可行...也可以访问主题 ang globals 提供程序(使用 themeProvider))

import  makeStyles from '@material-ui/core/styles'
import styles from './styles';

const useStyles =  makeStyles(theme => (styles(theme))); // here call styles function imported from styles.js
const SideNav = (drawerState, toggleDrawer) => 

  const classes = useStyles();

return (
 <Box className=classes.root>

    <Drawer className="drawer" anchor="left" open=drawerState onClose=() => toggleDrawer(false)>
      <NavList></NavList>
    </Drawer>

  </Box>
);


export default SideNav;

在styles.js中

const styles = (theme) => 
return (
    root: 
        '& .drawer': 
            backgroundColor:'red'
        
    
);

export default styles;

makeStyles 通过参数获取主题 所以你可以为每个内部带有箭头函数的组件创建一个styles.js 从可以访问主题提供程序的 makeStyles 调用。

【讨论】:

【参考方案6】:

您需要将对象传递给useStyles,而不是字符串。

所以而不是:

const classes = useStyles(backgroundColor);

你应该有:

const classes = useStyles(props);

const classes = useStyles(backgroundColor);

然后你可以使用:

color: theme.palette.getContrastText(props.backgroundColor).

这是一个工作示例: https://codesandbox.io/s/o7xryjnmly

【讨论】:

以上是关于如何在 makeStyles 中使用“主题”和“道具”?的主要内容,如果未能解决你的问题,请参考以下文章

使用 makeStyles 在另一个选定的类中嵌套类

如何在 Reactjs Material UI 上使用 CSS @media 响应 makeStyles?

Material-UI Typescript 如何在组件类中从 makeStyle() 创建样式实例

在 TS 中将 props 传递给 makeStyle

在 React 中使用 material-ui makeStyles 的钩子调用无效

material-ui makeStyles:如何按标签名称设置样式?