MUI Styles with Hook, Styled Component, HOC - rkaku/udemy-typescript-react GitHub Wiki

@material-ui/styles

yarn add @material-ui/core @material-ui/styles formik yup formik-material-ui styled-components

yarn add @material-ui/core

yarn add @material-ui/styles

yarn add formik yup

yarn add formik-material-ui

yarn add styled-components

// Re-export with a default theme
import { makeStyles } from '@material-ui/core/styles';

// Original module with no default theme
import { makeStyles } from '@material-ui/styles';

Hook API

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

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

export default function Hook() {
  const classes = useStyles();
  return <Button className={classes.root}>Hook</Button>;
}


<Button className={classes.root}>Styled with Hook API</Button>

Styled components API

import React from 'react';
import { styled } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const MyButton = styled(Button)({
  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',
});

export default function StyledComponents() {
  return <MyButton>Styled Components</MyButton>;
}


<MyButton>Styled with styled-components API</MyButton>

Higher-order component API

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const styles = {
  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 HigherOrderComponent(props) {
  const { classes } = props;
  return <Button className={classes.root}>Higher-order component</Button>;
}

HigherOrderComponent.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(HigherOrderComponent);

Nesting selectors

const useStyles = makeStyles({

  root: {
    padding: 16,
    color: 'red',

    '& p': {
      color: 'green',

      '& span': {
        color: 'blue'
      }
    }
  },
});
<Paper className={classes.root}>
  This is red since it is inside the paper.
  <p>
    This is green since it is inside the paragraph{' '}
    <span>and this is blue since it is inside the span</span>
  </p>
</Paper>

Adapting based on props

const useStyles = makeStyles({

  // style rule
  foo: props => ({
    backgroundColor: props.backgroundColor,
  }),

  bar: {
    // CSS property
    color: props => props.color,
  },
});


function MyComponent() {

  // Simulated props for the purpose of the example
  const props = { backgroundColor: 'black', color: 'white' };

  // Pass the props as the first argument of useStyles()
  const classes = useStyles(props);

  return <div className={`${classes.foo} ${classes.bar}`} />
}

Adapting the hook API

import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';


const useStyles = makeStyles({
  root: {
    background: props =>
      props.color === 'red'
        ? 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)'
        : 'linear-gradient(45deg, #2196F3 30%, #21CBF3 90%)',
    border: 0,
    borderRadius: 3,
    boxShadow: props =>
      props.color === 'red'
        ? '0 3px 5px 2px rgba(255, 105, 135, .3)'
        : '0 3px 5px 2px rgba(33, 203, 243, .3)',
    color: 'white',
    height: 48,
    padding: '0 30px',
    margin: 8,
  },
});
function MyButton(props) {
  const { color, ...other } = props;
  const classes = useStyles(props);
  return <Button className={classes.root} {...other} />;
}


MyButton.propTypes = {
  color: PropTypes.oneOf(['blue', 'red']).isRequired,
};


export default function AdaptingHook() {
  return (
    <React.Fragment>
      <MyButton color="red">Red</MyButton>
      <MyButton color="blue">Blue</MyButton>
    </React.Fragment>
  );
}

Adapting the styled components API

import React from 'react';
import { styled } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';


const MyButton = styled(({ color, ...other }) => <Button {...other} />)({
  background: props =>
    props.color === 'red'
      ? 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)'
      : 'linear-gradient(45deg, #2196F3 30%, #21CBF3 90%)',
  border: 0,
  borderRadius: 3,
  boxShadow: props =>
    props.color === 'red'
      ? '0 3px 5px 2px rgba(255, 105, 135, .3)'
      : '0 3px 5px 2px rgba(33, 203, 243, .3)',
  color: 'white',
  height: 48,
  padding: '0 30px',
  margin: 8,
});

Adapting the higher-order component API

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';


const styles = {
  root: {
    background: props =>
      props.color === 'red'
        ? 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)'
        : 'linear-gradient(45deg, #2196F3 30%, #21CBF3 90%)',
    border: 0,
    borderRadius: 3,
    boxShadow: props =>
      props.color === 'red'
        ? '0 3px 5px 2px rgba(255, 105, 135, .3)'
        : '0 3px 5px 2px rgba(33, 203, 243, .3)',
    color: 'white',
    height: 48,
    padding: '0 30px',
    margin: 8,
  },
};
function MyButtonRaw(props) {
  const { classes, color, ...other } = props;
  return <Button className={classes.root} {...other} />;
}


MyButtonRaw.propTypes = {
  /**
   * Override or extend the styles applied to the component.
   */
  classes: PropTypes.object.isRequired,
  color: PropTypes.oneOf(['blue', 'red']).isRequired,
};


const MyButton = withStyles(styles)(MyButtonRaw);

export default function AdaptingHOC() {
  return (
    <React.Fragment>
      <MyButton color="red">Red</MyButton>
      <MyButton color="blue">Blue</MyButton>
    </React.Fragment>
  );
}

Theme Provider

import React from 'react';
import PropTypes from 'prop-types';
import { ThemeProvider, useTheme, makeStyles } from '@material-ui/core/styles';


const useStyles = makeStyles(theme => ({
  root: props => ({
    backgroundColor: props.backgroundColor,
    color: theme.color,
  }),
}));
const Component = React.memo(props => {
  const classes = useStyles(props);
  const theme = useTheme();

  const rendered = React.useRef(1);
  React.useEffect(() => {
    rendered.current += 1;
  });

  return (
    <div className={classes.root}>
      rendered {rendered.current} times
      <br />
      color: {theme.color}
      <br />
      backgroundColor: {props.backgroundColor}
    </div>
  );
});

Component.propTypes = {
  backgroundColor: PropTypes.string.isRequired,
};
export default function StressTest() {
  const [backgroundColor, setBackgroundColor] = React.useState('#2196f3');
  const handleBackgroundColorChange = event => {
    setBackgroundColor(event.target.value);
  };

  const [color, setColor] = React.useState('#ffffff');
  const handleColorChange = event => {
    setColor(event.target.value);
  };

  const theme = React.useMemo(() => ({ color }), [color]);

  return (
    <ThemeProvider theme={theme}>
      <div>
        <fieldset>
          <div>
            <label htmlFor="color">theme color: </label>
            <input id="color" type="color" onChange={handleColorChange} value={color} />
          </div>
          <div>
            <label htmlFor="background-color">background-color property: </label>
            <input
              id="background-color"
              type="color"
              onChange={handleBackgroundColorChange}
              value={backgroundColor}
            />
          </div>
        </fieldset>
        <Component backgroundColor={backgroundColor} />
      </div>
    </ThemeProvider>
  );
}
⚠️ **GitHub.com Fallback** ⚠️