如何在 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 获得的预期效果。几个问题,考虑到我仍然想要相同的效果(绿色按钮黄色文本)使用某种 类 覆盖的方法(这对我来说以前似乎有意义)。
- 我对如何传递 类 作为使用 useStyles 覆盖其中部分内容的理解有何错误?
- 我应该如何处理它?
- 如果我使用了错误的方法,为什么 material-ui 仍然在 parent 具有 child 没有的样式时给我警告?
the key something
provided to the classes prop is not implemented in [Child]
- 旧方法 (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;"
。
考虑一个呈现按钮的组件,并说明该按钮应具有红色背景和黄色文本颜色。还有一个 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 获得的预期效果。几个问题,考虑到我仍然想要相同的效果(绿色按钮黄色文本)使用某种 类 覆盖的方法(这对我来说以前似乎有意义)。
- 我对如何传递 类 作为使用 useStyles 覆盖其中部分内容的理解有何错误?
- 我应该如何处理它?
- 如果我使用了错误的方法,为什么 material-ui 仍然在 parent 具有 child 没有的样式时给我警告?
the key
something
provided to the classes prop is not implemented in [Child] - 旧方法 (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;"
。