Почему это происходит?
Если у вас есть два класса 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