How to use useStyle to style Class Component in Material Ui - javascript

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
);
}
}

Related

Why cant I export and use my custom js styles?

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;

React native navigation useTheme()

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}>
)
}

React.js: How to implement dark/light mode in body toggling with useContext?

I am trying to create a background theme which will switch on onClick. On onClick it must change the background color of body in react app. I've managed to implement useContext, and now it toggles and changes the list items color in Header component. How to set it to body as well? Any help will be appreciated.
Here is my useContext color component
import React from 'react'
export const themes = {
light: {
foreground: '#ffffff',
},
blue: {
foreground: 'blue',
},
}
export default React.createContext({
theme: themes.light,
switchTheme: () => {},
})
onClick Button component
import React, { useContext } from 'react'
import ThemeContext from './context'
import './ThemedButton.scss'
const ThemedButton = () => {
const { switchTheme } = useContext(ThemeContext)
return (
<>
<button className="btn" onClick={switchTheme}>
Switch
</button>
</>
)
}
export default ThemedButton
App.js
import React, { useState } from 'react'
import SearchBar from './components/SearchBar';
import useCountries from './Hooks/useCountries';
import MainTable from './components/MainTable';
import ThemeButton from './useContext/ThemedButton';
import ThemeContext from './useContext/context';
import { searchProps } from './types';
import { themes } from './useContext/context';
import Routes from './Routes';
import './App.scss'
export default function App() {
const [search, setSearch] = useState('')
const [data] = useCountries(search)
const [context, setContext] = useState({
theme: themes.light,
switchTheme: () => {
setContext((current) => ({
...current,
theme: current.theme === themes.light ? themes.blue : themes.light,
}))
},
})
const handleChange: React.ReactEventHandler<HTMLInputElement> = (e): void => {
setSearch(e.currentTarget.value)
}
return (
<div className="App">
<SearchBar handleChange={handleChange} search={search as searchProps} />
<ThemeContext.Provider value={context}>
<ThemeButton />
<MainTable countries={data} />
</ThemeContext.Provider>
<Routes />
</div>
)
}
Header component
import React, { useContext } from 'react'
import ThemeContext from '../../useContext/context'
import './Header.scss'
export default function Header() {
const { theme } = useContext(ThemeContext)
return (
<div className="header">
<ul className="HeadtableRow" style={{ color: theme.foreground }}> // here it's set to change list items color
<li>Flag</li>
<li>Name</li>
<li>Language</li>
<li>Population</li>
<li>Region</li>
</ul>
</div>
)
}
If you want to change your body tag in your application you need to modify DOM and you can add this code to your Header.js (or any other file under your context) file:
useEffect(() => {
const body = document.getElementsByTagName("body");
body[0].style.backgroundColor = theme.foreground
},[])
*** Don't forget to import useEffect
*** Inline style like below is a better approach than modifying DOM directly
<div className="App" style={{backgroundColor: context.theme.foreground}}>
//For under context files just use theme.foreground
<SearchBar handleChange={handleChange} search={search as searchProps} />
<ThemeContext.Provider value={context}>
<ThemeButton />
<MainTable countries={data} />
</ThemeContext.Provider>
<Routes />
</div>

Applying styles to materialui component

`
import React, { Component } from 'react';
import Header from './Components/UI/header';
import { Box, Paper } from '#material-ui/core';
import { ThemeProvider, withStyles} from '#material-ui/core/styles';
const styles = () => ({
overrides: {
'MuiPaper-root': {
root: {
backgroundColor: '#345f',
}
}
}
});
export class App extends Component {
render() {
const classes = this.props;
return(<ThemeProvider theme={theme}>
<Paper classes={classes.overrides}>
<Box display="flex" justifyContent="center" alignItems="center" height={1}>
<Header />
</Box>
</Paper>
</ThemeProvider>);
}
}
export default withStyles(styles)(App);
`project img link
Im trying to apply a different background color to the paper api component. When i run the code it generates the same base styles.
You don't need to worry about the MUI generated styles or root. This will set your local <Paper /> component's background
const styles = () => ({
overrides: {
backgroundColor: '#345f',
}
});

How to extend or merge Styled Components theme

I have a Styled Components-based component library with its own set of theme settings that for the most part will never need to be overridden. I'm in the process of pulling this component library into another project that also uses Style Components and has its own theme. How can I import components from the component library and this project and ensure that each of them are only provided with theme values from their corresponding repo? I don't want to override my component library theme, I'd like to manage 2 separate themes so that my component library has access to a default theme and this other project can define a separate theme object for it's own components
Example:
Separate Project
const theme = {
colors: {
error: '#f23f3f',
}
}
import { SeparateProjectThemeProvider } from 'separate-proj';
class App extends React.Component {
render () {
return (
<SeparateProjectThemeProvider theme={theme}>
<h1>Hello</h1>
</SeparateProjectThemeProvider>
)
}
}
Component Library
const theme = {
colors: {
brand: '#3bbdca',
}
}
import { ThemeProvider } from "styled-components";
import defaultTheme from "./theme-settings";
const mergeThemes = (theme1, theme2) => {
const mergedTheme = { ...theme1, ...theme2 };
return mergedTheme;
};
const CustomThemeProvider = props => {
const customTheme = {
custom: Object.assign({}, defaultTheme)
};
return (
<ThemeProvider theme={mergeThemes(customTheme, props.theme)}>
{props.children}
</ThemeProvider>
);
};
export default CustomThemeProvider;
The code below will demonstrate a couple options -- either pre-wrapping each of your component-lib components with the appropriate theme provider (WrappedTitle) or wrapping as you use them ("Hello Component World!" portion).
// Sample component-lib/index.js
import React from 'react';
import styled from "styled-components";
import {ThemeProvider} from "styled-components";
const theme = {
titleColor: "green"
};
export const CompLibThemeProvider = props => {
const customTheme = Object.assign({}, theme, props.theme);
return (
<ThemeProvider theme={customTheme}>
{props.children}
</ThemeProvider>
);
};
export const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: ${props => props.theme.titleColor};
`;
export const WrappedTitle = (props) => {
return (<CompLibThemeProvider><Title {...props}/></CompLibThemeProvider>);
};
And here is some sample project code:
// App.js
import React from 'react';
import styled from 'styled-components';
import {Title, CompLibThemeProvider, WrappedTitle} from 'component-lib';
import {ThemeProvider} from "styled-components";
const theme = {
titleColor: "red"
};
export const BigTitle = styled.h1`
font-size: 5em;
text-align: center;
color: ${props => props.theme.titleColor};
`;
const ProjectThemeProvider = props => {
return (
<ThemeProvider theme={Object.assign({}, theme, props.theme)}>
{props.children}
</ThemeProvider>
);
};
const App = () => {
return (
<>
<ProjectThemeProvider>
<>
<BigTitle>Hello Big World!</BigTitle>
<WrappedTitle>Hello Pre-wrapped World!</WrappedTitle>
</>
</ProjectThemeProvider>
<CompLibThemeProvider><Title>Hello Component World!</Title></CompLibThemeProvider>
</>
);
}
export default App;

Categories