如何在 material-ui 中使用 makeStyles 和 useStyles 覆盖 类?

How to override classes using makeStyles and useStyles in material-ui?

考虑一个呈现按钮的组件,并说明该按钮应具有红色背景和黄色文本颜色。还有一个 Parent 组件使用这个 child 但是说,黄色很好,但我希望背景颜色是绿色。

withStyles

使用旧的 withStyles 没有问题。

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

const parentStyles = {
  root: {
    background: "green"
  }
};
const childStyles = {
  root: {
    background: "red"
  },
  label: {
    color: "yellow"
  }
};

const ChildWithStyles = withStyles(childStyles)(({ classes }) => {
  return <Button classes={classes}>Button in Child withStyles</Button>;
});

const ParentWithStyles = withStyles(parentStyles)(({ classes }) => {
  return <ChildWithStyles classes={classes} />;
});


export default ParentWithStyles;

https://codesandbox.io/s/passing-classes-using-withstyles-w17xs?file=/demo.tsx

makeStyles/useStyles

让我们试试 makeStyles/useStyles 并按照 material-ui.com 上的指南 Overriding styles - classes prop 进行操作。

import React from "react";
import { makeStyles } from "@material-ui/styles";
import { Button } from "@material-ui/core";

const parentStyles = {
  root: {
    background: "green"
  }
};
const childStyles = {
  root: {
    background: "red"
  },
  label: {
    color: "yellow"
  }
};

// useStyles variant does NOT let me override classes
const useParentStyles = makeStyles(parentStyles);
const useChildStyles = makeStyles(childStyles);

const ChildUseStyles = ({ classes: classesOverride }) => {
  const classes = useChildStyles({ classes: classesOverride });
  return (
    <>
      <Button classes={classes}>Button1 in Child useStyles</Button>
      <Button classes={classesOverride}>Button2 in Child useStyles</Button>
    </>
  );
};
const AnotherChildUseStyles = props => {
  const classes = useChildStyles(props);
  return (
    <>
      <Button classes={classes}>Button3 in Child useStyles</Button>
    </>
  );
};
const ParentUseStyles = () => {
  const classes = useParentStyles();
  return <>
    <ChildUseStyles classes={classes} />
    <AnotherChildUseStyles classes={classes} />
  </>
};

export default ParentUseStyles;

https://codesandbox.io/s/passing-classes-using-usestyles-6x5hf?file=/demo.tsx

似乎无法获得我使用 withStyles 获得的预期效果。几个问题,考虑到我仍然想要相同的效果(绿色按钮黄色文本)使用某种 类 覆盖的方法(这对我来说以前似乎有意义)。

顺便说一句,我知道 this solution 但是当你想要覆盖的内容太多时,这似乎很麻烦。

const useStyles = makeStyles({
  root: {
    backgroundColor: 'red',
    color: props => props.color, // <-- this
  },
});

function MyComponent(props) {
  const classes = useStyles(props);
  return <div className={classes.root} />;
}

withStyles 中的功能很少。它几乎只是一个为 makeStyles / useStyles 提供 HOC 接口的包装器。因此 withStyles 中的所有功能在 makeStyles 中仍然可用。

您没有获得预期效果的原因仅仅是因为执行顺序。

而不是:

const useParentStyles = makeStyles(parentStyles);
const useChildStyles = makeStyles(childStyles);

你应该有:

const useChildStyles = makeStyles(childStyles);
const useParentStyles = makeStyles(parentStyles);

调用 makeStyles 的顺序决定了 <head> 中相应样式表的顺序,当 specificity 其他方面相同时,该顺序决定了哪些样式获胜(后来的风格胜过早期的风格)。使用 withStyles 更难弄错该顺序,因为您用来覆盖其他东西的包装器通常会在它包装的东西之后定义。通过多次调用 makeStyles,可以更轻松地执行任意顺序,而不必将覆盖放在它们应该影响的基本样式之后。

理解这一点的关键是认识到您并不是真正传递覆盖,而是一组 类 与新的 类 成为 merged。如果 childClasses.root === 'child_root_1'parentClasses.root === 'parent_root_1',则合并结果为 mergedClasses.root === 'child_root_1 parent_root_1',这意味着任何将其 className 设置为 mergedClasses.root 的元素都接收 CSS 类 .最终结果(至于什么覆盖什么)完全取决于 CSS 两个 类.

中样式的特殊性

相关回答:

  • Internal implementation of "makeStyles" in React Material-UI?

在 Material-ui 4.11.x 使用 makeStyles 创建样式时 使用 createStyles 包装封闭样式,此样式的优先级高于默认样式。

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    backdrop: {
      zIndex: theme.zIndex.drawer + 1,
      color: '#fff',
    },
  }),
);

您可以尝试删除 createStyles 并查看差异。 来自 https://material-ui.com/components/backdrop/

的代码源

使用 withStyles 实现此目的的一种方法如下,可以帮助覆盖 css classes.

假设您要覆盖名为“.myclass”的 class,其中包含 "position: absolute;":

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

const styles = {
    "@global": {
      ".myClass": {
        position: "relative", 
      }
   }
};

const TestComponent = (props) =>  (
     <>
         <SomeComponent {...props}>
     </>
);    

export default withStyles(styles)(TestComponent);

执行此操作后,您将 <SomeComponent/> 上定义的 .myClass 的定义覆盖为 "position: relative;"