Я получаю следующую ошибку всякий раз, когда пытаюсь использовать makeStyles() с компонентом с методами жизненного цикла:
Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- You might have more than one copy of React in the same app
Ниже приведен небольшой пример кода, выдающего эту ошибку. Другие примеры также назначают классы дочерним элементам. Я не могу найти в документации MUI ничего, что бы показывало другие способы использования makeStyles и возможности использования методов жизненного цикла.
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import { Container, makeStyles } from '@material-ui/core';
import LogoButtonCard from '../molecules/Cards/LogoButtonCard';
const useStyles = makeStyles(theme => ({
root: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
}));
const classes = useStyles();
class Welcome extends Component {
render() {
if (this.props.auth.isAuthenticated()) {
return <Redirect to = "/" />;
}
return (
<Container maxWidth = {false} className = {classes.root}>
<LogoButtonCard
buttonText = "Enter"
headerText = "Welcome to PlatformX"
buttonAction = {this.props.auth.login}
/>
</Container>
);
}
}
export default Welcome;





Привет, вместо использования хука API вы должны использовать API компонента более высокого порядка, как уже упоминалось здесь
Я изменю пример в документации, чтобы удовлетворить ваши потребности в компоненте класса.
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/styles';
import Button from '@material-ui/core/Button';
const styles = theme => ({
root: {
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
border: 0,
borderRadius: 3,
boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
color: 'white',
height: 48,
padding: '0 30px',
},
});
class HigherOrderComponentUsageExample extends React.Component {
render(){
const { classes } = this.props;
return (
<Button className = {classes.root}>This component is passed to an HOC</Button>
);
}
}
HigherOrderComponentUsageExample.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(HigherOrderComponentUsageExample);
@ThePartyTurtle, да, передача реквизита, как обычно. использование его будет в другом файле js, будет таким же, как и раньше. просто импортируйте HigherOrderComponent из HigherOrderComponent.js.
О, попался. Оказывается, я был сбит с толку, потому что не видел «экспорт по умолчанию со стилями (стили) (HigherOrderComponent);» синтаксиса, и я был сбит с толку, если это была функция, которую мне нужно было вызвать... Прошло много времени с тех пор, как я в последний раз разрабатывал веб-приложение, и я в последний раз использовал TypeScript, ха-ха. Спасибо за разъяснения.
Я бегал по кругу с этой ошибкой и ошибкой invalid hook call. Спасибо, что направили меня в правильном направлении!
Это хорошо, но я могу как-то props в это вникнуть? Мне нужно сделать условные стили.
@Jax-p посмотри мое решение
@VikasKumar Как при таком подходе я могу использовать тему приложения в своих стилях? Ф.э. отправить: {маржа: appTheme.spacing(3, 0, 2),},
Не могли бы вы добавить типизацию для TypeScript, чтобы узнать, что содержит объект classes?
Спасибо. Но проблема! Вы не использовали theme в своем styles теле (@SergeyAldoukhov это уже говорил). Когда я его использую, я получаю эту ошибку: "Невозможно прочитать свойство "X" неопределенного" и undefined точно theme! Я попробовал withStyles(styles(myDefinedMuiTheme))(...), и он работал правильно.
@Китсон, Вероятно, вы использовали makeStyles()(styles = makeStyles(theme => ({...})). Кроме того, если вам нужен стиль, зависящий от темы, см. мой предыдущий комментарий.
Это должен быть ответ.
Привет, будущие гуглеры: пожалуйста, используйте import { withStyles } from '@material-ui/core/styles', а не так, как указано в ответе, из-за github.com/mui-org/material-ui/issues/…
В итоге мы прекратили использование компонентов класса и создали функциональные компоненты используя useEffect() из API хуков для методов жизненного цикла. Это позволяет вам по-прежнему использовать makeStyles() с методами жизненного цикла без усложнения создания компонентов более высокого порядка. Что намного проще.
Пример:
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { Redirect } from 'react-router-dom';
import { Container, makeStyles } from '@material-ui/core';
import LogoButtonCard from '../molecules/Cards/LogoButtonCard';
const useStyles = makeStyles(theme => ({
root: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
margin: theme.spacing(1)
},
highlight: {
backgroundColor: 'red',
}
}));
// Highlight is a bool
const Welcome = ({highlight}) => {
const [userName, setUserName] = useState('');
const [isAuthenticated, setIsAuthenticated] = useState(true);
const classes = useStyles();
useEffect(() => {
axios.get('example.com/api/username/12')
.then(res => setUserName(res.userName));
}, []);
if (!isAuthenticated()) {
return <Redirect to = "/" />;
}
return (
<Container maxWidth = {false} className = {highlight ? classes.highlight : classes.root}>
<LogoButtonCard
buttonText = "Enter"
headerText = {isAuthenticated && `Welcome, ${userName}`}
buttonAction = {login}
/>
</Container>
);
}
}
export default Welcome;
Я думаю, что для людей, использующих обновление React 16.8 Hooks или выше, переход на функцию — идеальное решение. В 16.8 функции могут обращаться к хукам состояния и жизненного цикла.
Я сбит с толку, почему это получило отрицательные голоса. React ясно дал понять, что классы заменяются функциональными компонентами с хуками. http://reactjs.org/docs/…
Я не понизил голос, но очень сложно установить начальное состояние ленивым способом, используя xhr при использовании функционального компонента. С компонентом класса я могу установить начальное состояние на все, что захочу, затем использовать ajax, а затем setState после получения ответа. Я совершенно не знаю, как сделать это красиво с помощью функции.
Вы бы использовали useEffect. В приведенном выше случае вы устанавливаете начальное состояние userName в пустую строку, затем после выполнения вызова API, обеспечивающего useEffect, вы будете использовать setUserName(response). Я добавлю пример выше и ссылку на статью с дополнительной информацией об использовании useEffect для методов жизненного цикла. dev.to/прототип/…
За это проголосовали против, потому что функциональное программирование отстой в реальных приложениях, которым нужна архитектура. Это усиливает и без того распространенную тенденцию js-программистов делать большие какашки спагетти-кода, которые очень, очень трудно читать/следовать и которые невозможно разделить на разумные компоненты. Если React продвигается таким образом, они совершают большую ошибку, и я не буду следовать за ними.
Вместо преобразования класса в функцию простым шагом было бы создать функцию, включающую jsx для компонента, который использует «классы», в вашем случае <container></container>, а затем вызвать эту функцию внутри возврата класса render( ) в качестве тега. Таким образом, вы перемещаете крючок на функцию из класса. Это сработало отлично для меня. В моем случае это был <table>, который я переместил в функцию TableStmt снаружи и назвал эту функцию внутри рендера как <TableStmt/>
useStyles — это хук React, который предназначен для использования в функциональных компонентах и не может использоваться в компонентах класса.
Hooks let you use state and other React features without writing a class.
Также вы должны вызвать useStyles хук внутри вашей функции как;
function Welcome() {
const classes = useStyles();
...
Если вы хотите использовать хуки, вот ваш краткий компонент класса, преобразованный в функциональный компонент;
import React from "react";
import { Container, makeStyles } from "@material-ui/core";
const useStyles = makeStyles({
root: {
background: "linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)",
border: 0,
borderRadius: 3,
boxShadow: "0 3px 5px 2px rgba(255, 105, 135, .3)",
color: "white",
height: 48,
padding: "0 30px"
}
});
function Welcome() {
const classes = useStyles();
return (
<Container className = {classes.root}>
<h1>Welcome</h1>
</Container>
);
}
export default Welcome;
? в ↓ CodeSandBox ↓
Я использовал withStyles вместо makeStyle
БЫВШИЙ :
import { withStyles } from '@material-ui/core/styles';
import React, {Component} from "react";
const useStyles = theme => ({
root: {
flexGrow: 1,
},
});
class App extends Component {
render() {
const { classes } = this.props;
return(
<div className = {classes.root}>
Test
</div>
)
}
}
export default withStyles(useStyles)(App)
Да, при использовании заданных компонентов MUI это решение подходило именно для того сценария, который у нас был. Должен быть принятый ответ
Это лучший ответ. Должен занять первое место
Еще одно решение можно использовать для компонентов класса - просто переопределите свойства темы MUI по умолчанию с помощью MuiThemeProvider. Это даст больше гибкости по сравнению с другими методами — вы можете использовать более одного MuiThemeProvider внутри вашего родительского компонента.
простые шаги:
пожалуйста, проверьте этот документ для более подробной информации: https://material-ui.com/customization/theming/
import React from 'react';
import PropTypes from 'prop-types';
import Button from '@material-ui/core/Button';
import { MuiThemeProvider } from '@material-ui/core/styles';
import { createMuiTheme } from '@material-ui/core/styles';
const InputTheme = createMuiTheme({
overrides: {
root: {
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
border: 0,
borderRadius: 3,
boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
color: 'white',
height: 48,
padding: '0 30px',
},
}
});
class HigherOrderComponent extends React.Component {
render(){
const { classes } = this.props;
return (
<MuiThemeProvider theme = {InputTheme}>
<Button className = {classes.root}>Higher-order component</Button>
</MuiThemeProvider>
);
}
}
HigherOrderComponent.propTypes = {
classes: PropTypes.object.isRequired,
};
export default HigherOrderComponent;Вы вызываете хук useStyles вне функции. Вот почему
В дополнение к ответу, предоставленному @vikas-kumar, также можно использовать props, которые устанавливаются для стилизованного компонента, например.
const styles = theme => ({
root: {
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
border: 0,
borderRadius: 3,
boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
color: 'white',
height: props => props.height,
padding: '0 30px',
},
});
Таким образом, height для применяемого стиля может регулироваться
<HigherOrderComponentUsageExample height = {48}/>
Дополнительные сведения о динамическом стиле см. здесь: https://material-ui.com/styles/basics/#adapting-the-higher-order-component-api.
Здорово! Да, примеры не показывают этот метод. Однако мне любопытно, как бы вы использовали свой «HighOrderComponent» в другом файле .js. Вы можете использовать "withStyles(styles)(HigherOrderComponent)" для его создания, но как ссылаться на стили в файле .js HigherOrderComponent? И вы просто передаете реквизит обычным способом?