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

时间:2019-07-08 06:52:57

标签: reactjs material-ui

我正在使用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 个答案:

答案 0 :(得分:1)

为什么会这样?

如果您将两个CSS类以相同的特异性程度应用于同一元素,那么获胜者将是该文档中最后定义的CSS类(基于<style>元素在文档中的顺序<head>在要设置样式的元素的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的marginmin-width的默认样式将胜过{{1}指定的自定义样式}。

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

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

当您将对makeStyles的调用移到一个单独的文件并导入其返回的makeStyles方法时,就会引入导入useStyles的可能性,之前导入Material-UI组件(在这种情况下,例如TextField)。

以下沙箱中的代码演示了这一点:https://codesandbox.io/s/makestyles-first-i1mwh

它可能在第一次热重装上起作用的原因是,useStyles makeStyles元素已被删除,然后在进行更改时添加到末尾。 Mui *样式元素不会更改,因此它们会保留在原处(在新的<style>样式元素之前,直到重新加载页面为止)。

由于makeStyleswithStyles中被调用,因此您无法轻易地使用Higher-order component API(即makeStyles)以这种方式射击自己的脚,因此您将始终导入withStyles包装的组件,然后再将其作为参数传递。


我该如何解决?

有几种方法可以解决此问题。一种方法是仅确保在导入Material-UI组件(例如withStyles后后导入useStyles函数。

更改:

TextField

改为:

import { useStyles } from "./styles";
import TextField from "@material-ui/core/TextField";

这在这里得到证明:https://codesandbox.io/s/import-textfield-first-9qybd

这是相当脆弱的,但是如果您在import TextField from "@material-ui/core/TextField"; import { useStyles } from "./styles"; 中具有一种以上类型的组件的样式并从许多文件中导入styles.js,因为要使其可靠地工作,您就必须依赖导入styles.js的第一个位置之前,由styles.js设置样式的Material-UI组件的所有。


解决此问题的另一种方法是导出Material-UI组件的样式版本,而不是导出styles.js函数。然后,您只需导入此自定义组件而不是Material-UI组件即可。

useStyles

在此处有两个不同的语法选项对此进行了演示:https://codesandbox.io/s/import-styled-textfield-1ytxl

答案 1 :(得分:0)

我遇到了类似的问题,并设法解决了以下问题

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

我后来还发现了一篇关于这个 here 的文章。

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

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