So I have this component that I am trying to write in react manner. Where each of the major containers are separated as React class component.
Now I know how to use withStyles with one component :
export default withStyles(styles)(MyComponent);
But when you have more than two components, how do you use withStyles.
Here's the code :
class AtmanPage extends Component {
render() {
return (
<AtmanAppBar />
);
}
}
class AtmanAppBar extends Component {
render() {
return (
<div className= {this.props.classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton className= {this.props.classes.menubutton} color="contrast" aria-label="Menu">
<MenuIcon />
</IconButton>
<Typography type="title" color="inherit" className={this.props.classes.flex}>
Title
</Typography>
<Button color="contrast">Login</Button>
</Toolbar>
</AppBar>
</div>
);
}
}
const styles = theme => ({
root: {
marginTop: theme.spacing.unit * 3,
width: '100%',
},
flex: {
flex: 1,
},
menuButton: {
marginLeft: -12,
marginRight: 20,
},
});
export default withStyles(styles) AtmanPage ?;
Now the question mark is about what else should be done to pass the styles as a prop to AtmanAppBar through AtmanPage.
Your issue is not related to withStyles but in the way you organize your components and exports.
Solution 1:
You can put each component in a separate file and use
export default withStyles(styles)(MyComponent);
in each file as you have mentioned in your post.
Solution 2:
You can do a simple export for both of your classes if you wish to keep them in the same file:
export const StyledAtmanAppBar = withStyles(styles)(AtmanAppBar);
export const StylesAtmanPage = withStyles(styles)(AtmanPage);
Then you need to import them like so in another file:
import {StyledAtmanAppBar, StylesAtmanPage} from './path/to/your/file';
Looking to handle this shizzle myself I came across a helpful util to use Styled-Components™-like API via Material-UI.
Gist example
After importing it as:
import styled from '../utils/styled';
you can create many Styled-Components-lookalikes in one file:
const List = styled('ul')(theme => ({
padding: theme.spacing.unit,
margin: 0,
}));
One difference with default withStyles() API is, that this util applies the styles to the root class, so you cannot nest many styles styles for one component (probably could be easily upgraded to allow that tbh).
But it's really handy for simple styles re-usability without the need to create too many files.
Credit to the (probable) author
Related
can somebody explain how pass in the defauklt theme in Material UI5
in Material UI6 i use to do it like this
const useStyles = makeStyles((theme) => ({
home: {
display: "flex",
paddingTop: "8rem",
width: "100vw",
height: "100vh",
backgroundColor: theme.palette.primary.dark,
color: "white",
},
}));
but as i got throught M-UI5 docs (as far as i found) there is no explanation on how it can be done , the only part they mention about makeStyle it contains this code in this page docs
+import { makeStyles } from '#mui/styles';
+import { createTheme, ThemeProvider } from '#mui/material/styles';
+const theme = createTheme();
const useStyles = makeStyles((theme) => ({
background: theme.palette.primary.main,
}));
function Component() {
const classes = useStyles();
return <div className={classes.root} />
}
// In the root of your app
function App(props) {
- return <Component />;
+ return <ThemeProvider theme={theme}><Component {...props} /></ThemeProvider>;
}
so am i suppose to run createTheme() on every component to get the theme? , apology if i missed out an obvious thing in the docs , probably coz my poor english
The part you are missing is from this part of the migration guide: https://mui.com/material-ui/guides/migration-v4/#style-library.
if you are using JSS style overrides for your components (for example overrides created by makeStyles), you will need to take care of the CSS injection order. To do so, you need to have the StyledEngineProvider with the injectFirst option at the top of your component tree.
Without this, the default styles for the MUI Card in your About component win over the styles specified via classes.about where the styles overlap (e.g. background).
Changing your AllProviders component to the following (just adding <StyledEngineProvider injectFirst>) fixes it:
import React from "react";
import CountriesProvider from "./countries-context";
import QuestionsProvider from "./questions-context";
import {
ThemeProvider,
createTheme,
StyledEngineProvider
} from "#mui/material/styles";
const theme = createTheme();
const AllProviders = (props) => {
return (
<StyledEngineProvider injectFirst>
<QuestionsProvider>
<ThemeProvider theme={theme}>
<CountriesProvider>{props.children}</CountriesProvider>
</ThemeProvider>
</QuestionsProvider>
</StyledEngineProvider>
);
};
export default AllProviders;
https://codesandbox.io/s/funny-flower-w9dzen?file=/src/store/AllProviders.js:303-342
The theme was being passed in fine without this change (otherwise you would have had errors when it tried to access parts of the theme), but the CSS injection order was not correct.
This is react-native question but similar concepts can be applied to react.
I want to create a CustomView in react-native. I am using typescript.
So far, I have:
const styles = StyleSheet.create({
container: {
backgroundColor: '#ffffff',
borderRadius: 10,
}
});
type CustomViewProps= {
width: number,
height: number,
marginTop?: string | number,
}
const CustomView = ({ width, height, marginTop }: CustomViewProps) => (
<View style={[styles.container, { height, width, marginTop }]} />
);
This is ok so far because only 3 props are being used: width, height and marginTop.
However, this is not reusable and it can become verbose if I need to add many more props.
So, the question is: How can I make CustomView receive any props as a native component View could receive?
My guess is I should delete CustomViewProps. Then, I should make the props inherit from the same type that the native component View does. However, I am struggling with it.
Since you are creating CustomViewProps, I assume that you want to add some specific behaviours to your native component above the already written behaviours of that component.
Let's create an example.
I want to create a button with some specific behaviours but i want it to behave, in other cases, like a normal TouchableOpacity component. For example, i want to add a "loading" state which will show a loader inside instead of its content.
So the logic is: create your custom props and merge you custom props with native's default props
import React, { FC, ReactElement } from 'react'
import { ActivityIndicator, TouchableOpacity, TouchableOpacityProps, StyleSheet } from 'react-native'
type MyProps = {
loading?: boolean
children: ReactElement
}
const MyButton: FC<MyProps & TouchableOpacityProps> = (props: MyProps & TouchableOpacityProps) => (
<TouchableOpacity {...props} disabled={props.disabled || props.loading} style={[styles.button, props.style]}>
{props.loading ? <ActivityIndicator /> : props.children}
</TouchableOpacity>
)
const styles = StyleSheet.create({
button: {
backgroundColor: 'yellow',
borderColor: 'black',
borderWidth: 1,
borderRadius: 10,
padding: 10
},
})
export default MyButton
The loading prop will be responsible for both content of the button or is disabled prop. The TouchableOpacity component will receive every compatible prop (autosuggest will be enabled because you have assigned the TouchableOpacityProps). The styles.button will behave like default style but will be overwritten if you specify something different in your style prop. That's it!
Im using the makeStyles() function in material-UI's react library, and am getting the following error
Hooks can only be called inside the body of a function component.
Below is an example of the kind of code I am using.
const useStyles = makeStyles(theme => ({
container: {
display: 'flex',
flexWrap: 'wrap',
},
textField: {
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
},
dense: {
marginTop: theme.spacing(2),
},
menu: {
width: 200,
},
}));
class Demo extends Component {
constructor(props) {
super(props);
}
render() {
const classes = useStyles();
return (
<TextField
className={classes.textField}
>
<MenuItem>Demo</MenuItem>
</TextField>
)
}
}
I know the error is being thrown because I'm trying to use makeStyles() in my class component (As shown above).
However, I'm curious if there is an alternative to makeStyles() for class components in Material-UI's react library, or what the syntax would be to get the functionality of make-styles in a class component.
makeStyles is just a high order function (returns a hook) to apply styles in functional components. You can always use withStyles, which is an HOC for the exact same purpose and works for both class an functional components
import { withStyles } from '#material-ui/styles'
const styles = {
root: {
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)'
}
};
class Component extends React.Component{
render(){
const { classes } = this.props
return <div className={classes.foo} />
}
}
export default withStyles(styles)(Component)
I have a page made up of many sub-components. The page folder holds the page file, external styles file and each sub-components folders - which also consists of their own style.
I'm not sure how to set up an external shared common style file for all sub-components along with external styles for each of the sub-components.
Ie. DemoStyles.js is the common styles and Demo.js is where are the sub-components are called.
Demo.js:
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import styles from "./DemoStyles";
import Red from "./red/Red";
import Blue from "./blue/Blue";
function SharedStyles(props) {
return (
<React.Fragment>
<Red />
<Blue />
</React.Fragment>
);
}
SharedStyles.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(SharedStyles);
DemoStyles.js:
export default theme => ({
title: {
color: "white",
fontSize: 30
}
});
The title style is not being applied.
The className is set in the Red.js file:
TL;DR:
I need one common external style file to apply to all subcomponents living in one folder; and each subcomponent needs their own external style specific to it.
Here is the code sample: https://codesandbox.io/s/rypoqk07lo
SOLVED:
I solved this by importing the demoStyles into the RedStyles.js file and then calling it with the spread operator and passing theme as an argument like so:
RedStyles.js
import demoStyles from "../DemoStyles";
export default theme => ({
...demoStyles(theme),
red: {
backgroundColor: "red"
}
});
code sample updated as well
You forgot to pass the classes props on Demo.js to your components like you do on <Red /> and <Blue />.
const { classes } = props;
return (
<React.Fragment>
<Red classes={classes} />
<Blue classes={classes} />
</React.Fragment>
);
Its good to remember that Material-UI has themes support. It's better to use it on Demo.js depending of what you trying to do.
I have a simple React JS component that wraps around the really cool react ChartistGraph component. The only issue is that the styling is seemingly overridden by the ChartistGraph default CSS. There is a lot of info on the regular Chartist js package but not much on the React JS package.
As you can see, I'm trying to change the fill color two ways: through style classes and through a prop that supported on the component.
import React from 'react';
import { Paper, withStyles } from 'material-ui';
import ChartistGraph from 'react-chartist';
const styles = theme => ({
graphStyle: {
fill: 'red',
},
});
const CustomChart = ({ classes, graph }) => {
return (
<Paper>
<ChartistGraph
className={classes.graphStyle}
data={graph.data}
options={graph.options}
type={graph.type}
style={{ fill: 'red' }}
/>
</Paper>
);
};
export default withStyles(styles)(CustomChart);
A picture of the styles of the chart
You can use jss's nested rules (included by default in material-ui):
const styles = theme => ({
graphStyle: {
'& .ct-label': { fill: 'red' },
},
});
Full code:
import React from 'react';
import { Paper, withStyles } from 'material-ui';
import ChartistGraph from 'react-chartist';
const styles = theme => ({
graphStyle: {
'& .ct-label': { fill: 'red' },
},
});
const CustomChart = ({ classes, graph }) => {
return (
<Paper>
<ChartistGraph
className={classes.graphStyle}
data={graph.data}
options={graph.options}
type={graph.type}
// style={{ fill: 'red' }} // omitted
/>
</Paper>
);
};
export default withStyles(styles)(CustomChart);
I got into similar issue recently.React-Chartist is built on top of react not material-ui.When you inspect,you found regular css class names,not "material ui-ish" class-names(like MuiTable-root,MuiTable-selectedRow,etc).So ,imho,it won't support material-ui methods (withStyle/makeStyle) and rules.
But what you can do is:-
create a css file and put your styles there
And import it where you want
.You can import it on the main file of your app(index.js or whatever it is) since every css in your app will bundle in one file.