从单个文件导出的 Material UI v4 makeStyles 不会在刷新时保留样式

IT技术 reactjs material-ui
2021-04-11 01:46:55

我正在使用 Material UI v4,我正在从单个文件中导出我的样式,但是这些样式在其他组件中不起作用。styles.js

const useStyles = makeStyles(theme => ({
    root: {
      display: 'flex',
    },
    // textField component styles
    textFieldInput: {
      margin: theme.spacing(2),
      width: 250,
      minWidth: 250,
    },
    formControl: {
      margin: theme.spacing(2),
      minWidth: 120,
    },


})
export {useStyles}

在我的组件文件中

    ....
    const classes = useStyles(styles);

    return (
        <TextField
            className={classes.textFieldInput}
            label={label}
            placeholder={label}
            error={touched && invalid}
            helperText={touched && error}
            {...input}
            disabled={disabled || false}
            readOnly={readOnly || false}
            required={required || false}
            InputProps={{ readOnly, ...custom }}
            {...custom}
        />
    );
     ....

当我在我的组件中使用它时,样式将在第一次热重载时起作用,但之后样式不会有任何影响,为什么?以及我如何解决这个问题

2个回答

为什么会这样?

如果您将两个 CSS 类应用于具有相同特定程度的同一元素,那么获胜者将是文档中最后定义的 CSS 类(基于 中<style>元素的顺序<head>,而不是类的顺序class正在设置样式的元素属性中的名称字符串)。

此页面是一个带有两个 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类被施加到经由文本域的指定的类相同的元件className特性(例如,从textFieldInput类makeStyles/useStyles)。由于MuiFormControl<style>元素后出现makeStyles <style>元素,MuiFormControl的默认样式marginmin-width拉拢由造型指定的自定义makeStyles

这些<style>元素的顺序由makeStyles调用的顺序控制对于给定 Material-UI 组件的默认样式,makeStyles在第一次导入组件时调用。

对于典型的使用模式, wheremakeStyles在同一个 JavaScript 文件中调用,然后调用useStyles并将类传递给 Material-UI 组件,顺序将始终是您想要的,因为 Material-UI 组件的导入将在调用之前发生到makeStyles

当您将调用移动makeStyles到一个单独的文件并导入useStyles它返回方法时,您引入了useStyles 导入 Material-UI 组件之前导入的可能性(例如本例中的 TextField)。

这在此沙箱中的代码中进行了演示:https : //codesandbox.io/s/makestyles-first-i1mwh

它可能在第一次热重载时起作用的原因是该makeStyles <style>元素被删除,然后在您进行更改时添加到最后。Mui* 样式元素不会更改,因此它们保持原样(在makeStyles重新加载页面之前,在新样式元素之前)。

使用高阶组件 API(即withStyles),您不能以这种方式轻松地用这种方式射击自己,因为它makeStyles是在内部调用的,withStyles因此withStyles在将其作为参数传递之前,您将始终导入被包装的组件


我怎样才能解决这个问题?

有几种方法可以解决这个问题。一种方法是仅仅确保您导入useStyles功能后,进口材料的UI组件,例如TextField

改变:

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.jsstyles.js从许多文件中导入,那么为了让它可靠地工作,您依赖于导入所有styles.js在第一个位置之前设置样式的 Material-UI 组件您导入的styles.js.


解决此问题的另一种方法是导出 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

如果您有多个样式包的副本,您也可以看到此行为:material-ui.com/getting-started/faq/...
2021-06-02 01:46:55
Ryan 关于为什么它不起作用是正确的,我猜是因为我的 css 样式被覆盖了。所以我决定使用 '!important' 来确保它不会被覆盖。因此,我使用了 {margin: '15px !important'} 而不是 {margin: '15px'} 并且它起作用了!希望这可以帮助。
2021-06-07 01:46:55
非常感谢您的回答!出于某种原因,在其他组件不起作用之后导入 useStyles,但可能是我这边的问题,将尝试根据您分享的想法进行调试!感谢您抽出时间进行解释!
2021-06-08 01:46:55

我一直面临着类似的问题,并设法解决它如下

root: {
        '&&': {
            width: "128px",
            height: "128px",
            margin: "8px",
        }
    },

后来我还在这里找到了一篇关于此的文章

使用双与号“&&”会增加/加倍特异性/优先级。因此,对于我想覆盖的任何类,我在声明的类中添加了“&&”。

这为我解决了问题,没有任何明显的缺点,但我不知道这是否真的是一个好习惯。如果有人知道更多关于为什么不使用它的信息,请告诉我。