How can I make use of the Material UI styling options inside of a TSX class-component?
Due to the Typed Props and State I can't seem to figure out how to do it.
My Code below throws an "Invalid hook" error in side the componentWillMount method, where I try to load the created styles in to my component state.
How would you go about using the Material UI makeStyles method in a TSX component?
import { makeStyles } from '#material-ui/core/styles';
import Card from '#material-ui/core/Card';
import CardActionArea from '#material-ui/core/CardActionArea';
import CardMedia from '#material-ui/core/CardMedia';
import CardContent from '#material-ui/core/CardContent';
import CardActions from '#material-ui/core/CardActions';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
import { IShowMinimal } from "../../interface/show.minimal";
interface IShowCardProps {
show: IShowMinimal
}
interface IShowCardState {
materialUIclasses: any
}
const useStyles = makeStyles({
card: {
maxWidth: 345,
},
media: {
height: 140,
},
});
export class ShowCard extends Component<IShowCardProps, IShowCardState> {
constructor(props: IShowCardProps) {
super(props);
console.log("hi");
this.state = {
materialUIclasses: {}
}
console.log("Show", this.props.show);
}
componentWillMount() {
this.setState({
materialUIclasses: useStyles({})
});
}
render(): JSX.Element {
return (
<article>
<Card>
<CardActionArea>
<CardMedia
className={this.state.materialUIclasses.media}
image={this.props.show.image}
title={`Thumbnail for the show ${this.props.show.name}`}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{this.props.show.name}
</Typography>
</CardContent>
</CardActionArea>
</Card>
</article>
)
}
}```
makeStyles returns react hook, so you can't use it inside Component. Hooks are only for functional components. Use withStyles HOC from material-UI.
import { withStyles } from '#material-ui/core/styles';
import Card from '#material-ui/core/Card';
import CardActionArea from '#material-ui/core/CardActionArea';
import CardMedia from '#material-ui/core/CardMedia';
import CardContent from '#material-ui/core/CardContent';
import CardActions from '#material-ui/core/CardActions';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
import { IShowMinimal } from "../../interface/show.minimal";
interface IShowCardProps {
show: IShowMinimal,
classes: any
}
interface IShowCardState {
materialUIclasses: any
}
const styles = {
card: {
maxWidth: 345,
},
media: {
height: 140,
},
};
class ShowCard extends Component<IShowCardProps, IShowCardState> {
constructor(props: IShowCardProps) {
super(props);
this.state = {
materialUIclasses: {}
}
}
render(): JSX.Element {
return (
<article>
<Card>
<CardActionArea>
<CardMedia
className={this.props.classes.media}
image={this.props.show.image}
title={`Thumbnail for the show ${this.props.show.name}`}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{this.props.show.name}
</Typography>
</CardContent>
</CardActionArea>
</Card>
</article>
)
}
}
export default withStyles(styles)(ShowCard);
Related
Hi i've found this https://github.com/Learus/react-material-ui-carousel to use it on my website. But i've encountered 2 problems:
In order to set the autoPlay state, i have to change it to class which leads to unable to use const classes = useStyles() so does anyone know what should i do?
I have 3 jpg photos saved in the img folder under the same directory and i have no idea why the photos cant be loaded in my localhost.
Here is my code:
import React from 'react';
import { createMuiTheme } from '#material-ui/core';
import { ThemeProvider } from '#material-ui/core';
import { makeStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import Button from '#material-ui/core/Button';
import Tooltip from '#material-ui/core/Tooltip';
import Carousel from 'react-material-ui-carousel';
import CarouselSlide from 'react-material-ui-carousel';
import Card from '#material-ui/core/Card';
import CardMedia from '#material-ui/core/CardMedia';
import CardContent from '#material-ui/core/CardContent';
const theme = createMuiTheme ({
palette: {
primary:{
main:'#3c52b2'
}
}
})
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
Button: {
"&:hover": {
backgroundColor: "#fff !important"
}
},
title: {
flexGrow: 1,
},
}));
export default function UMainPage (){
const pictures = [
{image:'./2.jpg', title:'Iu 1'},
{image:'./3.jpg', title:'Iu 2'},
{image:'./4.jpg', title:'Iu 3'}
];
const classes = useStyles();
return (
<ThemeProvider theme={theme}>
<AppBar position="static">
<Toolbar>
<Typography variant="h6" className={classes.title}>
清动订馆平台
</Typography>
<Button color="inherit">首页</Button>
<Button color="inherit">历史订单</Button>
<Tooltip disableFocusListener disableTouchListener title="登录账号">
<Button color="inherit">未登录</Button>
</Tooltip>
</Toolbar>
</AppBar>
<Carousel>
{pictures.map(({image, title}) => (
<CarouselSlide key={image}>
<Card>
<CardMedia
image={image}
title={title}
style={{
height: 0,
paddingTop: '25%',
}}
/>
<CardContent>
<Typography>{title}</Typography>
</CardContent>
</Card>
</CarouselSlide>
))}
</Carousel>
</ThemeProvider>
);
}
In order to set autoPlay you should pass it to Carousel like this:
<Carousel autoPlay>
...
</Carousel>
If you want to have ability to change it you should keep in state:
const [autoPlay, setAutoPlay] = useState(true);
You should import your images first and then keep them in the pictures array:
import image2 from "./2.jpg";
import image3 from "./3.jpg";
import image4 from "./4.jpg";
...
const pictures = [
{ image: image2, title: "Iu 1" },
{ image: image3, title: "Iu 2" },
{ image: image4, title: "Iu 3" },
];
I have a
<ListSubheader className={this.props.classes.listSubHeaderRoot}>Teszt Színház</ListSubheader>
in a List.
And set style like:
const styles = theme => ({
// ...
listSubHeaderRoot: {
backgroundColor: '#E5E5E5',
color: '#252525',
height: '22px'
/* To change the font, use the fontFamily rule */
}
})
but result looks like:
Why text is out of the grace box? How can I prevent it?
Here the whole code:
import React, { Component } from "react";
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemIcon from '#material-ui/core/ListItemIcon';
import ListItemText from '#material-ui/core/ListItemText';
import ArrowForwardIos from '#material-ui/icons/ArrowForwardIos';
import ListSubheader from '#material-ui/core/ListSubheader';
import Switch from '#material-ui/core/Switch';
import TextField from '#material-ui/core/TextField';
import ListItemAvatar from '#material-ui/core/ListItemAvatar';
import Avatar from '#material-ui/core/Avatar';
import FolderIcon from '#material-ui/icons/Folder';
import ListItemSecondaryAction from '#material-ui/core/ListItemSecondaryAction';
import DeleteIcon from '#material-ui/icons/Delete';
import IconButton from '#material-ui/core/IconButton';
import Box from '#material-ui/core/Box';
import { withStyles } from '#material-ui/core/styles';
const styles = theme => ({
listSubHeaderRoot: {
backgroundColor: '#E5E5E5',
color: '#252525',
height: '22px'
/* To change the font, use the fontFamily rule */
}
})
class App extends Component {
render() {
return <div>
<ListSubheader className={this.props.classes.listSubHeaderRoot}>Teszt Színház</ListSubheader>
<ListItem button>
<Box textAlign="left" style={{width: 150 }}>Teszt Esemény</Box>
<ListItemText secondaryTypographyProps={{ align: "right" }} secondary=""/>
<IconButton edge="end" aria-label="delete">
<ArrowForwardIos />
</IconButton>
</ListItem>
</div>;
}
}
export default withStyles(styles)(App);
Need to set:
lineHeight: "22px"
I would like to convert this Functional Component
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { makeStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/core/Menu';
import FacebookLoginButton from "./components/FacebookLoginButton"
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
}));
function App() {
const classes = useStyles();
return (
<div className="App">
<AppBar position="static">
<Toolbar>
<IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
Tiket.hu
</Typography>
<Button color="inherit">Search</Button>
<Button color="inherit">Basket</Button>
<FacebookLoginButton/>
</Toolbar>
</AppBar>
</div>
);
}
export default App;
to Class Component, like below here, but I get an error. Do you know what is wrong?
import React, { Component } from "react";
import logo from './logo.svg';
import './App.css';
import { makeStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/core/Menu';
import FacebookLoginButton from "./components/FacebookLoginButton"
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
}));
class App extends Component {
classes = useStyles();
render() {
return <div className="App">
<AppBar position="static">
<Toolbar>
<IconButton edge="start" className={this.classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" className={this.classes.title}>
Tiket.hu
</Typography>
<Button color="inherit">Search</Button>
<Button color="inherit">Basket</Button>
<FacebookLoginButton/>
</Toolbar>
</AppBar>
</div>;
}
}
export default App;
Do you know what is wrong? How should I convert differently?
You must use the material ui HOC with a class component
import React, { Component } from "react";
import logo from './logo.svg';
import './App.css';
import { makeStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/core/Menu';
import FacebookLoginButton from "./components/FacebookLoginButton"
// import this
import { withStyles } from '#material-ui/core/styles';
// make this
const styles = theme => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
})
class App extends Component {
render() {
return <div className="App">
<AppBar position="static">
<Toolbar>
<IconButton edge="start" className={this.props.classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" className={this.props.classes.title}>
Tiket.hu
</Typography>
<Button color="inherit">Search</Button>
<Button color="inherit">Basket</Button>
<FacebookLoginButton/>
</Toolbar>
</AppBar>
</div>;
}
}
export default withStyles(styles)(App);
Material-ui MakeStyles is using the hook pattern, which is not allowed inside class components.
Use withStyles HOC instead.
import { withStyles } from '#material-ui/core/styles';
const styles = {
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
};
class App extends Component {
const { classes } = this.props;
the rest of your component...
}
export default withStyles(styles)(App);
You are using hooks inside a Class Component this isn't allowed. Hooks are specifically made to work with Functional Components
So i'm still finding my feet with reactjs.net + asp.net core. I've imported latest version (v1) of material-ui.com into the mix. I am trying to combine the two but having issues with classes/props composition.
The code below is verbatim of what i've been told i need and found via hours of searching online. Yet, this.props.classes continue to throw undefined errors.
Is there a step i'm missing?
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
const homeStyles = {
root: {
height: 200 ,
flexGrow: 1,
},
grow: {
flexGrow: 1,
},
menuButton: {
marginLeft: -12,
marginRight: 20,
},
};
export class Home extends React.Component {
displayName = Home.name
constructor(props) {
super(props);
console.log("Props: " + props != null);
}
render() {
const { classes } = this.props;
return (
<div>
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton style={classes.menuButton} color="inherit" aria-label="Menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" color="inherit" style={classes.grow}>Undefined? {(this.props == undefined).toString()}</Typography>
<Button color="inherit">Login</Button>
</Toolbar>
</AppBar>
</div>
</div>
);
}
}
Home.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(homeStyles)(Home)
react-router changes the link but the page does not change. When go to the address from URL it works but doesn't work when clicking button
ZWrapper.jsx
import React from 'react';
import { Link, NavLink } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { withStyles, createStyleSheet } from 'material-ui/styles';
import ZWrapperAppBar from 'app/components/Wrapper/ZWrapperAppBar';
import ZWrapperDrawer from 'app/components/Wrapper/ZWrapperDrawer';
const styleSheet = createStyleSheet('Main', {
root: {
width: '100%',
flexGrow: 1,
align: 'center',
direction: 'row'
},
flex: {
align: 'center',
direction: 'row',
justify: 'flex-end',
},
mainDrawer:{
position: 'relative',
width: 500
},
mainDrawerContent:{
height: '100%'
},
mainDrawerBottomNav:{
position: 'absolute',
bottom: 0
},
typeContainer:{
margin: 0
}
});
export class ZWrapper extends React.Component{
PropTypes = {
classes: PropTypes.object.isRequired,
};
render(){
return(
<div className={styleSheet.root}>
<ZWrapperAppBar classes={styleSheet} />
<ZWrapperDrawer classes={styleSheet} />
{this.props.children}
</div>
)
}
}
// export default withStyles(styleSheet)(ZWrapper);
export default connect((state)=>{
return { drawerOpen: state.mainContainerDrawerOpen }
})(ZWrapper);
ZWrapperAppBar.jsx
import React from 'react';
import { Link, NavLink } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { withStyles, createStyleSheet } from 'material-ui/styles';
import { AppBar, Toolbar, Typography, IconButton, Grid, Button } from 'material-ui';
import { lightGreen, green } from 'material-ui/colors';
import MenuIcon from 'material-ui-icons/Menu';
import LinkButton from 'app/components/material-ui-addons/LinkButton';
import {toggleOpenDrawer} from 'actions';
export class ZWrapperAppBar extends React.Component{
PropTypes = {
classes: PropTypes.object.isRequired,
};
render(){
var {dispatch, drawerOpen, classes} = this.props;
return(
<AppBar position="absolute" >
<Toolbar style={{backgroundColor: green.A400}} className={classes.mainAppBar}>
<IconButton color="contrast" aria-label="Menu" onClick={()=>{dispatch(toggleOpenDrawer())}}>
<MenuIcon />
</IconButton>
<Typography color="inherit" type="title">
Recipea
</Typography>
<Grid container className={classes.flex} align="center" direction="row" justify="flex-end" gutter={Number("8")}>
<Button component={Link} color="contrast" to="/Account/Login" >{'Get Started'}</Button>
</Grid>
</Toolbar>
</AppBar>
)
}
}
export default connect((state)=>{
return { drawerOpen: state.mainContainerDrawerOpen }
})(ZWrapperAppBar);
ZWrapperDrawer
import React from 'react';
import { Link, NavLink } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { withStyles, createStyleSheet } from 'material-ui/styles';
import { AppBar, Toolbar, Typography, Button, IconButton, Grid, Drawer, Divider } from 'material-ui';
import List, { ListItem, ListItemIcon, ListItemText } from 'material-ui/List';
import BottomNavigation, { BottomNavigationButton } from 'material-ui/BottomNavigation';
import { lightGreen, green, grey } from 'material-ui/colors';
import CloseIcon from 'material-ui-icons/Close';
import SettingsIcon from 'material-ui-icons/Settings';
import FavoriteIcon from 'material-ui-icons/Favorite';
import LocationOnIcon from 'material-ui-icons/LocationOn';
import ListItemWithLink from 'app/components/material-ui-addons/ListItemWithLink';
import {toggleOpenDrawer} from 'actions';
export class ZWrapperDrawer extends React.Component{
PropTypes = {
classes: PropTypes.object.isRequired,
};
render(){
var {dispatch, drawerOpen, classes} = this.props;
return(
<Drawer docked={false} open={drawerOpen} onRequestClose={()=>{dispatch(toggleOpenDrawer())}} className={classes.mainDrawer}>
<AppBar position="static" className={classes.mainAppBar}>
<Toolbar style={{backgroundColor: green.A400}}>
<Link to="/">
<Button>
<Typography type="title" style={{color: grey[50]}}>Recipea</Typography>
</Button>
</Link>
<Grid container className={classes.flex} align="center" direction="row" justify="flex-end" gutter={Number("8")}>
<IconButton color="contrast" aria-label="Menu" onClick={()=>{dispatch(toggleOpenDrawer())}}>
<CloseIcon />
</IconButton>
</Grid>
</Toolbar>
</AppBar>
<ListItem button>
<ListItemText primary="About" />
</ListItem>
<ListItemWithLink to="/About/Us" label="Us" />
<ListItemWithLink to="/About/OurHelper" label="Used Dependencies"/>
<BottomNavigation className={classes.mainDrawerBottomNav} showLabels>
<BottomNavigationButton label="Settings" icon={<SettingsIcon />} />
<BottomNavigationButton label="Favorites" icon={<FavoriteIcon />} />
<BottomNavigationButton label="Nearby" icon={<LocationOnIcon />} />
</BottomNavigation>
</Drawer>
)
}
}
export default connect((state)=>{
return {
drawerOpen: state.mainContainerDrawerOpen
}
})(ZWrapperDrawer);
My Router
import React from 'react';
import {BrowserRouter as Router, Switch, Route, Redirect} from 'react-router-dom';
import MainPage from 'MainPage';
import ZWrapper from 'ZWrapper';
import AccountSignUp from 'AccountSignUp';
export default(
<Router>
<ZWrapper>
<Switch>
<Route exact path='/' component={MainPage}/>
<Route exact path='/Account/SignUp' component={AccountSignUp}/>
</Switch>
</ZWrapper>
</Router>
)
app.jsx
//Modules
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
// import 'typeface-roboto';
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
import injectTapEventPlugin from 'react-tap-event-plugin';
// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
injectTapEventPlugin();
import Router from 'app/router/';
import {configure} from 'configureStore';
var store = configure();
//App CSS
require('applicationStyles');
//App JS
require('myJS/all.jsx');
// override material-ui theme
const theme = createMuiTheme({
overrides:{
MuiGrid:{
'gutter-xs-8':{
margin: '0 -8px'
},
'gutter-xs-16':{
margin: '0 -8px'
},
'gutter-xs-24':{
margin: '0 -8px'
},
'gutter-xs-40':{
margin: '0 -8px'
},
},
},
})
//render
ReactDOM.render(
<Provider store={store}>
<MuiThemeProvider theme={theme}>
{Router}
</MuiThemeProvider>
</Provider>,
document.getElementById('app')
);
Material-UI: v1-alpha
React: 15.5.4
React-router-dom: 4.1.1
Browser: chrome (59.0.3071.115)
Add change the folowing code to add withRouter to from react-router-dom and change the export default to solve this issue
import { Link, NavLink, withRouter } from 'react-router-dom';
export default withRouter(
connect((state)=>{
return { drawerOpen: state.mainContainerDrawerOpen }
})(ZWrapperDrawer)
);