为什么会这样?
如果您有两个 CSS 类以相同的特定程度应用于同一个元素,那么获胜者将是文档中最后定义的 CSS 类(基于 <style> 元素在 @ 987654328@, NOT 被设置样式的元素的class 属性中的类名字符串的顺序)。
This page 是一个带有两个 TextField 元素的示例,可以重现您的问题。如果您打开浏览器开发人员工具并查看<style> 元素,您将看到makeStyles 的样式首先出现,然后是TextField 的样式(例如MuiFormControl)。我在下面展示了一个缩写版本:
<style data-jss="" data-meta="makeStyles">
.makeStyles-textFieldInput-1 {
margin: 32px;
min-width: 250px;
}
</style>
<style data-jss="" data-meta="MuiFormControl">
.MuiFormControl-root {
border: 0;
margin: 0;
display: inline-flex;
padding: 0;
position: relative;
min-width: 0;
flex-direction: column;
vertical-align: top;
}
.MuiFormControl-marginNormal {
margin-top: 16px;
margin-bottom: 8px;
}
.MuiFormControl-marginDense {
margin-top: 8px;
margin-bottom: 4px;
}
.MuiFormControl-fullWidth {
width: 100%;
}
</style>
<style data-jss="" data-meta="MuiTextField">
</style>
MuiFormControl-root 类应用于与通过 TextField 的 className 属性指定的类相同的元素(例如 makeStyles/useStyles 中的 textFieldInput 类)。由于MuiFormControl <style> 元素出现在makeStyles <style> 元素之后,MuiFormControl 的margin 和min-width 的默认样式优于makeStyles 指定的自定义样式。
这些<style> 元素的顺序由调用makeStyles 的顺序控制。对于给定 Material-UI 组件的默认样式,在首次导入组件时调用 makeStyles。
对于典型的使用模式,makeStyles 在同一个 JavaScript 文件中调用,然后调用 useStyles 并将类传递给 Material-UI 组件,顺序将始终是您想要的,因为Material-UI 组件将在调用 makeStyles 之前发生。
当您将对makeStyles 的调用移动到一个单独的文件并导入它返回的useStyles 方法时,您引入了导入useStyles 的可能性在导入 Material-UI 组件之前(例如本例中的 TextField)。
这在此沙箱中的代码中得到了演示:https://codesandbox.io/s/makestyles-first-i1mwh
它可能在第一次热重载时起作用的原因是 makeStyles <style> 元素正在被删除,然后在您进行更改时添加到末尾。 Mui* 样式元素不会改变,因此它们会保持原样(在新的 makeStyles 样式元素之前,直到重新加载页面)。
由于makeStyles 在withStyles 中被调用,因此您不能使用Higher-order component API(即withStyles)以这种方式轻易地击中自己的脚,因此您将始终导入由withStyles 包装的组件在将其作为参数传递之前。
我该如何解决这个问题?
有几种方法可以解决这个问题。一种方法是确保在在导入 Material-UI 组件(如 TextField)之后导入 useStyles 函数。
变化:
import { useStyles } from "./styles";
import TextField from "@material-ui/core/TextField";
改为:
import TextField from "@material-ui/core/TextField";
import { useStyles } from "./styles";
此处演示:https://codesandbox.io/s/import-textfield-first-9qybd
这是相当脆弱的,但是如果您在 styles.js 中有多个类型的组件的样式并从许多文件中导入 styles.js,那么从那时起要使其可靠地工作,您就依赖于导入 all 在您导入styles.js 的第一个 位置之前由styles.js 设置样式的Material-UI 组件。
解决此问题的另一种方法是导出 Material-UI 组件的样式版本,而不是导出 useStyles 函数。然后你只需导入这个自定义组件而不是 Material-UI 组件。
import { withStyles } from "@material-ui/core/styles";
import MuiTextField from "@material-ui/core/TextField";
const styles = theme => ({
root: {
margin: theme.spacing(4),
minWidth: 250
}
});
export const TextField = withStyles(styles)(MuiTextField);
这里有几个不同的语法选项来演示:https://codesandbox.io/s/import-styled-textfield-1ytxl