【问题标题】:Material UI v4 makeStyles exported from a single file doesn't retain the styles on refresh从单个文件导出的 Material UI v4 makeStyles 在刷新时不保留样式
【发布时间】:2019-11-17 15:51:28
【问题描述】:

我正在使用 Material UI v4,我正在从单个文件中导出我的样式, 但是这些样式在其他组件中不起作用 样式.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}
        />
    );
     ....

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

【问题讨论】:

    标签: reactjs material-ui


    【解决方案1】:

    为什么会这样?

    如果您有两个 CSS 类以相同的特定程度应用于同一个元素,那么获胜者将是文档中最后定义的 CSS 类(基于 &lt;style&gt; 元素在 @ 987654328@, NOT 被设置样式的元素的class 属性中的类名字符串的顺序)。

    This page 是一个带有两个 TextField 元素的示例,可以重现您的问题。如果您打开浏览器开发人员工具并查看&lt;style&gt; 元素,您将看到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 &lt;style&gt; 元素出现在makeStyles &lt;style&gt; 元素之后,MuiFormControl 的marginmin-width 的默认样式优于makeStyles 指定的自定义样式。

    这些&lt;style&gt; 元素的顺序由调用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 &lt;style&gt; 元素正在被删除,然后在您进行更改时添加到末尾。 Mui* 样式元素不会改变,因此它们会保持原样(在新的 makeStyles 样式元素之前,直到重新加载页面)。

    由于makeStyleswithStyles 中被调用,因此您不能使用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

    【讨论】:

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

    我也遇到过类似的问题,解决方法如下

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

    后来我也找到了一篇关于这个here的文章。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 2021-05-11
      • 2021-12-29
      • 2021-09-11
      • 1970-01-01
      • 1970-01-01
      • 2021-09-22
      相关资源
      最近更新 更多