This my main class
import React, { Component } from 'react';
import { withStyles } from '#material-ui/core/styles';
import styles from './FoodStyles';
class Food extends Component {
render () {
return (
<div>
<h2 className="header">Food</h2>
</div>
)
}
}
export default withStyles(styles) (Food);
And this is my style class called FoodStyles.js
const styles = theme => ({
header: {
backgroundColor: 'red'
},
});
export default styles;
They both are in the same folder but still styles cannot be accessed
This could be the solution to your problem: (You need destructuring as done in line 7 for your styles to be used in your file.) With React, which fully embraces the ES6 syntax, destructuring adds a slew of benefits to improving your code.
Food.js:
import React, { Component } from 'react';
import { withStyles } from '#material-ui/core/styles';
import styles from './styles';
class Food extends Component {
render () {
const { classes } = this.props;
return (
<div>
<h2 className={classes.header}>Food</h2>
</div>
)
}
}
export default withStyles(styles)(Food);
styles.js:
const styles = theme => ({
header: {
backgroundColor: 'red'
},
});
export default styles;
Result:
Reasons to destructure:
1. Improves readability:
This is a huge upside in React when you’re passing down props. Once you take the time to destructure your props, you can get rid of props / this.props in front of each prop.
2. Shorter lines of code:
Insead of:
var object = { one: 1, two: 2, three: 3 }
var one = object.one;
var two = object.two;
var three = object.three
console.log(one, two, three) // prints 1, 2, 3
We can write:
let object = { one: 1, two: 2, three: 3 }
let { one, two, three } = object;
console.log(one, two, three) // prints 1, 2, 3
3. Syntactic sugar:
It makes code look nicer, more succinct, and like someone who knows what they’re doing wrote it.
I would just use makeStyles instead of withStyles.
App.jsx
import Food from "./Food";
const App = () => {
return (
<div className="App">
<Food />
</div>
);
};
export default App;
Food.jsx
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import styles from "./FoodStyles";
const useStyles = makeStyles(styles);
const Food = () => {
const classes = useStyles();
return (
<div>
<h2 className={classes.header}>Food</h2>
</div>
);
};
export default Food;
FoodStyles.js
const styles = (theme) => ({
header: {
backgroundColor: "red"
}
});
export default styles;
Related
When I implement a simple React component with Mui's withStyles HOC, I have to use the keyword "default" when exporting the component. Why can't I use the HOC in the return statement within the functional component?
Is there something about Js or ReactJs that I'm missing?
Since I am forced to export this component as default, I lose the possibility to use the named import functionality, without using another import/export layer in between.
Below is the current working code:
// Card.js
import React from "react";
import {
Card,
withStyles
} from "#material-ui/core";
const styles = theme => ({
card: {
margin: theme.spacing(2)
}
});
function CustomCard(props) {
const {classes} = props;
return (
<Card className={classes.card}>
Export me without being the default component.
</Card>
);
}
export default withStyles(styles)(MediaCard);
// Elsewhere.js
import CustomCard from "Card";
...
But i'd rather write something like this:
// Cards.js
import React from "react";
import {
Card,
withStyles
} from "#material-ui/core";
const styles = theme =\> ({
card: {
margin: theme.spacing(2)
},
anotherCard: {
margin: theme.spacing(4)
}
});
export function CustomCard(props) {
const {classes} = props;
return withStyles(styles)(
<Card className={classes.card}>
Jeah. I'm not the default component.
</Card>
);
}
export function AnotherCard(props) {
const {classes} = props;
return withStyles(styles)(
<Card className={classes.anotherCard}>
Jeah. I'm not the default component either.
</Card>
);
}
// Elsewhere.js
import { CustomCard, AnotherCard } from "Cards";
...
You can do it the way you want to but you to change the way you define your components. The technical reason is that all exports except default need to be named, otherwise you can't import them and know what's what. Since withStyles() returns a statement and not a named variable/function you can't export it without a name.
export const AnotherCard = withStyles(styles)((props) => {
const {classes} = props;
return (
<Card className={classes.anotherCard}>
Jeah. I'm not the default component either.
</Card>
);
});
The downside of this is of course now your components aren't hoisted.
I'm trying to access useTheme() directly from the styles
But so far my solution doesn't seem to work.
I'm not getting in error back.
Is there a way to do what I'm trying to do?
import { StyleSheet } from "react-native";
import { useTheme } from '#react-navigation/native'
export default function () {
const { colors } = useTheme();
const styles = GlobalStyles({ colors: colors })
return styles
}
const GlobalStyles = (props) => StyleSheet.create({
container: {
flex: 1,
backgroundColor: props.colors.backgroundColor,
},
})
Accessing style in component
import React from "react";
import GlobalStyles from "../globalStyles.js"
class Inventory extends React.Component {
render() {
return (
<View style={globalStyles.container}>
)
}
You have a couple of issues: you can only use a hook within a hook or a function component. So you could convert your global stylesheet into a hook:
import { StyleSheet } from "react-native";
import { useTheme } from '#react-navigation/native'
const getGlobalStyles = (props) => StyleSheet.create({
container: {
flex: 1,
backgroundColor: props.colors.backgroundColor,
},
});
function useGlobalStyles() {
const { colors } = useTheme();
// We only want to recompute the stylesheet on changes in color.
const styles = React.useMemo(() => getGlobalStyles({ colors }), [colors]);
return styles;
}
export default useGlobalStyles;
Then you can use the hook by converting your Inventory class component into a function component and using the new useGlobalStyles hook.
import React from "react";
import useGlobalStyles from "../globalStyles.js"
const Inventory = () => {
const globalStyles = useGlobalStyles();
return (
<View style={globalStyles.container}>
)
}
I am using React and Material-UI. Is there any way to export a class estended from React.Component? I want to use some React variables like state. If this is not possible, how can I use state?
Actual code (works):
import React from 'react';
import { Typography } from '#material-ui/core';
import { makeStyles } from '#material-ui/styles';
const styles = makeStyles(() => ({
style1: {
fontSize: '12px'
}
}));
const MyComponent = () => {
const classes = styles();
return(
<Typography className={classes.style1}>Hello World</Typography>
);
}
export default MyComponent;
What I am looking for:
import React, { Component } from 'react';
import { Typography } from '#material-ui/core';
import { makeStyles } from '#material-ui/styles';
export default class MyComponent extends Component {
constructor(props){
super(props);
this.classes = makeStyles(() => ({
style1: {
fontSize: '12px'
}
}));
}
render() {
return(
<Typography className={this.classes.style1}>Hello World</Typography>
);
}
}
You are using makeStyles(), which is used when your component is a functional component. makeStyles() is a Hooks API.
If you are using the Class component, then you must be using the HOC variant, which is withStyles
Example taken from here:
import React from 'react';
import { withStyles } from '#material-ui/core/styles';
const styles = {
root: {
backgroundColor: 'red',
},
};
function MyComponent(props) {
return <div className={props.classes.root} />;
}
export default withStyles(styles)(MyComponent);
withStyles() can be used for both functional and class components unlike makeStyles(), which can only be used for functional components.
You can also use decorator syntax for HOC variant like here. But you need to use this babel plugin like mentioned in the official material-ui docs:
import React from 'react';
import { withStyles } from '#material-ui/core/styles';
const styles = {
root: {
backgroundColor: 'red',
},
};
#withStyles(styles)
class MyComponent extends React.Component {
render () {
return <div className={this.props.classes.root} />;
}
}
export default MyComponent
I'm creating a component using material-ui withStylers and defaultProps, but when i try to use the props of the component, in the styles objects, i never get the value of my default props, only get the value if it is passed to the component.
My component structure is something like this:
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core";
const styles = theme => ({
ClassTest: {
anyAttr: props => console.log(props)
}
});
const Test = ({classes}) => {
return (
<span className={classes.ClassTest}/>
);
};
Test.defaultProps = {
val2: "hey"
};
Test.propTypes = {
val1: PropTypes.bool.isRequired,
val2: PropTypes.string,
};
export default withStyles(styles, { withTheme: true })(Test);
And i use like this
<Test val1="Hello">
I expect that the console log show something like this:
{
classes: {...},
val1: "Hello",
val2: "hey"
}
But instead, i got this
{
classes: {...},
val1: "Hello"
}
If I call the component that way:
<Test val1="Hello" val2="hey">
I got this:
{
classes: {...},
val1: "Hello",
val2: "hey"
}
So, the styles object shouldn't give the the value of the props, considering defaultProps? I'm doin it correctly or i miss something?
I'm using the following versions:
"#material-ui/core": "^4.3.0",
"react": "^16.8.6",
And I'm basing on this part of the documentation
https://material-ui.com/styles/basics/#adapting-based-on-props
withStyles is wrapping Test in a higher-order-component and has no visibility to the default props of Test. withStyles is adding to the properties of Test (injecting a classes prop), so the default props for Test can't be determined until after withStyles finishes its work (e.g. if Test had a default prop for classes, it wouldn't be leveraged when withStyles is providing classes, but the default could be leveraged when not wrapped by withStyles).
In the code below, I demonstrate three different approaches:
The first is the approach you tried which doesn't work because the default props aren't visible to withStyles.
The second approach applies the default props to the HOC returned by withStyles.
The third approach uses makeStyles/useStyles instead of withStyles which makes it possible to still have the default props on the initial component rather than the HOC.
All three approaches work when bgcolor is specified explicitly (orange), but only approaches 2 and 3 successfully see the default prop value.
import React from "react";
import ReactDOM from "react-dom";
import { withStyles, makeStyles } from "#material-ui/core/styles";
const styles = {
test: {
backgroundColor: props => props.bgcolor
}
};
const useStyles = makeStyles(styles);
const ApproachThatDoesNotWork = ({ classes }) => {
return <div className={classes.test}>ApproachThatDoesNotWork</div>;
};
ApproachThatDoesNotWork.defaultProps = {
bgcolor: "lightgreen"
};
const StyledApproachThatDoesNotWork = withStyles(styles)(
ApproachThatDoesNotWork
);
const DefaultPropsOnStyledHOC = ({ classes }) => {
return <div className={classes.test}>DefaultPropsOnStyledHOC</div>;
};
const StyledDefaultPropsOnStyledHOC = withStyles(styles)(
DefaultPropsOnStyledHOC
);
StyledDefaultPropsOnStyledHOC.defaultProps = {
bgcolor: "pink"
};
const MakeStylesAndUseStyles = props => {
const classes = useStyles(props);
return <div className={classes.test}>MakeStylesAndUseStyles</div>;
};
MakeStylesAndUseStyles.defaultProps = {
bgcolor: "lightblue"
};
function App() {
return (
<div className="App">
<StyledApproachThatDoesNotWork />
<StyledApproachThatDoesNotWork bgcolor="orange" />
<StyledDefaultPropsOnStyledHOC />
<StyledDefaultPropsOnStyledHOC bgcolor="orange" />
<MakeStylesAndUseStyles />
<MakeStylesAndUseStyles bgcolor="orange" />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
I want to use useStyle to style the Class Component . But this can be easily done hooks. but i want to use Component instead. But I cant figure out how to do this.
import React,{Component} from 'react';
import Avatar from '#material-ui/core/Avatar';
import { makeStyles } from '#material-ui/core/styles';
import LockOutlinedIcon from '#material-ui/icons/LockOutlined';
const useStyles = makeStyles(theme => ({
'#global': {
body: {
backgroundColor: theme.palette.common.white,
},
},
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
}
}));
class SignIn extends Component{
const classes = useStyle(); // how to assign UseStyle
render(){
return(
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
</div>
}
}
export default SignIn;
You can do it like this:
import { withStyles } from "#material-ui/core/styles";
const styles = theme => ({
root: {
backgroundColor: "red"
}
});
class ClassComponent extends Component {
state = {
searchNodes: ""
};
render() {
const { classes } = this.props;
return (
<div className={classes.root}>Hello!</div>
);
}
}
export default withStyles(styles, { withTheme: true })(ClassComponent);
Just ignore the withTheme: true if you aren't using a theme.
To get this working in TypeScript, a few changes are needed:
import { createStyles, withStyles, WithStyles } from "#material-ui/core/styles";
const styles = theme => createStyles({
root: {
backgroundColor: "red"
}
});
interface Props extends WithStyles<typeof styles>{ }
class ClassComponent extends Component<Props> {
// the rest of the code stays the same
for class Components you can use withStyles instead of makeStyles
import { withStyles } from '#material-ui/core/styles';
const useStyles = theme => ({
fab: {
position: 'fixed',
bottom: theme.spacing(2),
right: theme.spacing(2),
},
});
class ClassComponent extends Component {
render() {
const { classes } = this.props;
{/** your UI components... */}
}
}
export default withStyles(useStyles)(ClassComponent)
Hey I had a similar problem. I solved it by replacing makeStyles with withStyles and then at the point where do something like const classes = useStyle();, replace that with const classes = useStyle;
You notice useStyle is not supposed to be a function call but rather a variable assignment.
That should work fine after you've made those changes.
useStyles is a react hook. You can use it in function component only.
This line creates the hook:
const useStyles = makeStyles(theme => ({ /* ... */ });
You are using it inside the function component to create classes object:
const classes = useStyles();
Then in jsx you use classes:
<div className={classes.paper}>
Suggested resources:
https://material-ui.com/styles/basics/
https://reactjs.org/docs/hooks-intro.html
Like other answers already stated you should use withStyles to augment a component and pass the classes through the properties. I've taken the liberty to modify the Material-UI stress test example into a variant that uses a class component.
Note that the withTheme: true option is normally not needed when you simply want to use the styles. It is needed in this example because the actual value of the theme is used in the render. Setting this option makes theme available through the class properties. The classes prop should always be provided, even if this option is not set.
const useStyles = MaterialUI.withStyles((theme) => ({
root: (props) => ({
backgroundColor: props.backgroundColor,
color: theme.color,
}),
}), {withTheme: true});
const Component = useStyles(class extends React.Component {
rendered = 0;
render() {
const {classes, theme, backgroundColor} = this.props;
return (
<div className={classes.root}>
rendered {++this.rendered} times
<br />
color: {theme.color}
<br />
backgroundColor: {backgroundColor}
</div>
);
}
});
function StressTest() {
const [color, setColor] = React.useState('#8824bb');
const [backgroundColor, setBackgroundColor] = React.useState('#eae2ad');
const theme = React.useMemo(() => ({ color }), [color]);
const valueTo = setter => event => setter(event.target.value);
return (
<MaterialUI.ThemeProvider theme={theme}>
<div>
<fieldset>
<div>
<label htmlFor="color">theme color: </label>
<input
id="color"
type="color"
onChange={valueTo(setColor)}
value={color}
/>
</div>
<div>
<label htmlFor="background-color">background-color property: </label>
<input
id="background-color"
type="color"
onChange={valueTo(setBackgroundColor)}
value={backgroundColor}
/>
</div>
</fieldset>
<Component backgroundColor={backgroundColor} />
</div>
</MaterialUI.ThemeProvider>
);
}
ReactDOM.render(<StressTest />, document.querySelector("#root"));
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/#material-ui/core#4/umd/material-ui.production.min.js"></script>
<div id="root"></div>
Yet another way to do this, albeit a bit of a workaround.
Some may say this doesn't really answer the question, but I would argue that it does. The end result is useStyles() delivers the styling for a class-based yet multi-part parent component.
In my case I needed a standard Javascript class export so that I could call new MyClass() without a MyClass is not a constructor error.
import { Component } from "./react";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
someClassName: {
...
}
}));
export default class MyComponent extends Component {
render() {
return <RenderComponent {...this.props} />;
}
}
function RenderComponent(props) {
const classes = useStyles();
return (
/* JSX here */
);
}
how to add multiple classes in ClassName with class component
import { withStyles } from "#material-ui/core/styles";
const styles = theme => ({
root: {
backgroundColor: "red"
},
label: {
backGroundColor:"blue"
}
});
class ClassComponent extends Component {
state = {
searchNodes: ""
};
render() {
const { classes } = this.props;//
return (
<div className={classes.root + classes.label}>Hello!</div> //i want to add label style also with
);
}
}