I get the below error whenever I try to use makeStyles()
with a component with lifecycle methods:
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
Below is a small example of code that produces this error. Other examples assign classes to child items as well. I can't find anything in MUI's documentation that shows other ways to use makeStyles
and have the ability to use lifecycle methods.
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;
This question is related to
reactjs
material-ui
Instead of converting the class to a function, an easy step would be to create a function to include the jsx for the component which uses the 'classes', in your case the <container></container>
and then call this function inside the return of the class render() as a tag. This way you are moving out the hook to a function from the class. It worked perfectly for me. In my case it was a <table>
which i moved to a function- TableStmt outside and called this function inside the render as <TableStmt/>
I used withStyles
instead of makeStyle
EX :
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)
Hi instead of using hook API, you should use Higher-order component API as mentioned here
I'll modify the example in the documentation to suit your need for class component
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);
useStyles
is a React hook which are meant to be used in functional components and can not be used in class components.
Hooks let you use state and other React features without writing a class.
Also you should call useStyles
hook inside your function like;
function Welcome() {
const classes = useStyles();
...
If you want to use hooks, here is your brief class component changed into functional component;
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;
on ↓ CodeSandBox ↓
Another one solution can be used for class components - just override default MUI Theme properties with MuiThemeProvider. This will give more flexibility in comparison with other methods - you can use more than one MuiThemeProvider inside your parent component.
simple steps:
please, check this doc for more details: 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;
_x000D_
Source: Stackoverflow.com