Интерфейс материала v4 makeStyles, экспортированный из одного файла, не сохраняет стили при обновлении - PullRequest
1 голос
/ 08 июля 2019

Я использую 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}
        />
    );
     ....

когда я использую его в своих компонентах, стили будут работать при первой горячей перезагрузке, но после этого стили не будут иметь никакого эффекта, почему?и как я могу это исправить

1 Ответ

1 голос
/ 08 июля 2019

Почему это происходит?

Если у вас есть два класса CSS, примененные к одному и тому же элементу с одинаковой степенью специфичности, то победителем будет класс CSS, который определен последним в документе (на основепорядок элементов <style> в <head>, NOT порядок строк имени класса в атрибуте 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 применяется к тому же элементу, что и класс, указанный в свойстве TextField * 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, перед тем, как передать его в качестве параметра..


Как я могу это исправить?

Есть несколько способов решить эту проблему.Один из способов - просто убедиться, что вы импортируете useStyles функцию после импорта компонентов Material-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.js и импорт styles.js из многих файлов, с тех пор для его надежной работы вы зависите от импорта всех компонентов Material-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

...