Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

material-ui / How to style an HOC using 'withStyles()'?

My HOC :

const withPaper = Component => props => (
  <Paper>
    <Component {...props} />
  </Paper>
);

export default withPaper;

I want to style 'Paper' component using withStyles():

const styles = theme => ({
  root: {
    backgroundColor: 'green'
  }
});

const withPaper = ?? => ?? => (
  <Paper className={classes.root}>
    <Component {...props} />
  </Paper>
);

export default withStyles(styles)(withPaper);

How can I inject classes prop this case? My simple idea Component => ({classes, ...props}) => logs error.

TypeError: Cannot call a class as a function

like image 631
Peter Park Avatar asked Jun 11 '18 10:06

Peter Park


2 Answers

Answering my own question.

I ignored the returns of HOC. It returns 'Component' instead of 'React Element'. I'm not sure, but I think this is the reason that I couldn't inject classes from outside of HOC.

My solution that works well - styling inside of HOC:

const withPaper = Component => {
  const WithPaper = ({ classes, ...props }) => (
    <Paper className={classes.root}>
      <Component {...props} />
    </Paper>
  );

  const styles = theme => ({
    root: {
      backgroundColor: 'green'
    }
  });

  return withStyles(styles)(WithPaper);
};

export default withPaper;

FYI, TypeScript users can refer to Rahel's answer.

like image 73
Peter Park Avatar answered Oct 12 '22 22:10

Peter Park


I am in the process of learning Material-UI and TypeScript myself, and I was actually struggling with the very same thing :-) Apologies if you were looking for a JS solution, but the types being explicit might actually help:

import * as React from "react";
import createStyles from "@material-ui/core/styles/createStyles";
import { WithStyles } from "@material-ui/core";
import Paper from "@material-ui/core/Paper/Paper";
import { compose } from "recompose";
import withStyles from "@material-ui/core/styles/withStyles";

const styles = createStyles({
  root: {
    backgroundColor: "green"
  }
});

type WrapperProps = WithStyles<typeof styles>;

const withPaper = <P extends {}>(Component: React.ComponentType<P>) => {
  type Props = P & WrapperProps;

  return (props: Props) => {
    return (
      <Paper className={props.classes.root}>
        <Component {...props} />
      </Paper>
    );
  };
};

export default compose(withStyles(styles), withPaper);

Edit xvkwo6vzxz

Note the usage of recompose, to compose your higher-order components. If you mind this library-dependency, you can also do without:

export default (component: React.ComponentType) => withStyles(styles)(withPaper(component));
like image 28
Rahel Lüthy Avatar answered Oct 13 '22 00:10

Rahel Lüthy