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

Chr*_*eek 8 css overriding reactjs material-ui

考虑一个组件,它呈现一个按钮并说这个按钮应该有一个红色的背景和一个黄色的文本颜色。还有一个使用这个孩子的父组件,但说黄色很好,但我希望背景颜色为绿色。

带样式

使用旧的 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;
Run Code Online (Sandbox Code Playgroud)

使用 withStyles 的孩子中的按钮

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;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

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

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

  • 我对如何传递类作为使用 useStyles 覆盖它们的一部分的方式的理解有什么错误?
  • 我应该如何处理它?
  • 如果我使用了错误的方法,为什么当父母拥有孩子没有的样式时,material-ui 仍然给我一个警告?

    something提供给 classes 道具的键未在 [Child] 中实现

  • 旧方法(withStyles)与新方法的迁移是否记录在某处?

顺便说一句,我知道这个解决方案,但是当您想要覆盖太多时,这似乎很麻烦。

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

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

Rya*_*ell 6

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

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

代替:

const useParentStyles = makeStyles(parentStyles);
const useChildStyles = makeStyles(childStyles);
Run Code Online (Sandbox Code Playgroud)

你应该有:

const useChildStyles = makeStyles(childStyles);
const useParentStyles = makeStyles(parentStyles);
Run Code Online (Sandbox Code Playgroud)

使用 useStyles 编辑传递类

在该命令makeStyles被调用来确定在相应的样式表的顺序<head>,并且当特异性是否则相同的,即顺序决定哪些样式赢得(稍后样式笼络更早样式)。使用该顺序更难,withStyles因为您用来覆盖其他内容的包装器通常会在它包装的东西之后定义。通过多次调用,makeStyles可以更轻松地执行任意顺序,而不必将覆盖放在它们应该影响的基本样式之后。

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

相关回答:

  • 谢谢你!我不知道这就是覆盖实际上是如何完成的。我会注意并特别注意 makeStyles 的调用顺序。 (2认同)