小编典典

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

reactjs

我正在使用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}
        />
    );
     ....

当我在组件中使用样式时,样式将在第一次热重装时起作用,但是之后样式将不会产生任何效果,为什么会有这样的想法?以及我该如何解决


阅读 313

收藏
2020-07-22

共1个答案

小编典典

为什么会这样呢?

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

此页面是一个示例,其中包含两个重现您的问题的TextField元素。如果打开浏览器开发人员工具并查看其<style>元素,您将看到from样式makeStyles首先出现,然后是from样式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的默认样式为,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重新加载页面之前,它在新样式元素之前)。

您无法轻易地使用高阶组件API(即withStyles)来以这种方式射击自己的脚,因为在其中makeStyles被调用了,withStyles因此withStyles在将其作为参数传递之前,您始终会导入被包装的组件。


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

您可以通过几种方法解决此问题。一种方法是仅确保 在* 导入Material-UI组件(例如) 之后 导入useStyles函数。
*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.js和进口styles.js从许多文件,自那时以来它可靠地工作,你都依赖于进口
所有 由风格的材质,UI组件styles.js的前 第一 位置您导入的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

2020-07-22