Internal implementation of "makeStyles" in React Material-UI?

The purpose of this question is to understand what is happening under the hood. Every time I found the code with makeStyles() I feel that I am just doing a pure copy paste without understanding what is happening under the hood. So I thought of posting a question here so that some one can help me out.

I have seen the below kind of code in many React apps. I was so curious to know what is happening when we make a call to makeStyles(). So I jumped into its definition but I am not able to understand what does it mean. Can someone help me understand how to read/understand it.

What I understand here is that I am passing a function with parameter named theme. After passing that function I have no clue what is going on. I appreciate if some one help me figure out this as well.

// Calling makeStyles()
const useStyles = makeStyles(theme => ({
  root: {
    display: 'flex',
  },
  drawer: {
    [theme.breakpoints.up('sm')]: {
      width: drawerWidth,
      flexShrink: 0,
    },
  },
  appBar: {
    marginLeft: drawerWidth,
    [theme.breakpoints.up('sm')]: {
      width: `calc(100% - ${drawerWidth}px)`,
    },
  },
  menuButton: {
    marginRight: theme.spacing(2),
    [theme.breakpoints.up('sm')]: {
      display: 'none',
    },
  },
  toolbar: theme.mixins.toolbar,
  drawerPaper: {
    width: drawerWidth,
  },
  content: {
    flexGrow: 1,
    padding: theme.spacing(3),
  },
}));

//definition of makeStyles()
import { Theme as DefaultTheme } from './createMuiTheme';
import { Styles, WithStylesOptions } from '@material-ui/styles/withStyles';
import { StylesHook } from '@material-ui/styles/makeStyles';

export default function makeStyles<
  Theme = DefaultTheme,
  Props extends {} = {},
  ClassKey extends string = string
>(
  styles: Styles<Theme, Props, ClassKey>,
  options?: WithStylesOptions<Theme>,
): StylesHook<Styles<Theme, Props, ClassKey>>;

Solution 1:

High-level picture of inputs/outputs/side effects

makeStyles

  • overview: This function is typically called at the top-level within a JavaScript file (not from within a component/function), and it returns a function (typically called useStyles) that will be used from within a function component.
  • input: styles object or styles object creator function
    • If the input is an object, it is assumed that each property of the object defines a style rule. The property name is the rule name and the property value is an object with CSS properties and/or nested rules. Each style rule will later be used to generate a CSS class.
    • If the input is a function, it is assumed to be a function that receives the theme as an argument and then returns a styles object with the structure described in the case where the input is an object.
    • In the makeStyles function declaration, this input is called stylesOrCreator. This is then normalized by the getStylesCreator function to be an object with a create property that points at a function which will return a styles object.
  • output: useStyles function
    • The function returned by makeStyles is typically called useStyles and is a custom hook. This means that it can only be called from within a function component and must be called unconditionally.
    • At the point of returning this useStyles function, very little has happened. The function knows about its stylesCreator, but hasn't used it yet. Via the stylesCreator's options, the useStyles function knows an index that will later be used to determine the location in the <head> of the style sheet for these styles relative to the other style sheets generated by other calls to makeStyles/useStyles.
  • side effect: increments a global counter that is used to determine the index within the <head> of style sheets generated by makeStyles/useStyles.

useStyles

  • overview: This is the function returned by makeStyles. It should be called from within a function component to get a classes object described below.
  • optional input: props object
    • If passed, this is typically the props of the function component this is used in. This will then be passed as an argument to any style rules where the value is a function.
    • You can see examples of using this in the following answers:
      • Send Variable to withStyles in Material UI?
      • Using props to set '&:hover' background-color
      • How to use 'theme' and 'props' in makeStyles?
  • output: classes object
    • This object maps each style rule name in your styles object to a generated CSS class name. You can then leverage classes.rulename in your component rendering to apply that CSS class to an element.
  • side effect: Adds a style sheet to the DOM in the <head> containing a CSS class per style rule.

Where the main work occurs

The bulk of the magic happens when you call the useStyles function. The beginning of the function is here. Here are the key steps it performs:

  • Calls attach. The attach function does the following key steps:
    • Calls stylesCreator.create to get your styles object.
    • Leverages JSS to create a style sheet based on your styles object. It is also within here that JSS generates the class names that will be in the classes object.
    • Attaches this style sheet to the DOM at the appropriate location within the <head>.
  • Returns the classes object
  • If something happens to trigger re-creating the CSS or if the component unmounts, then detach is called to remove the previously generated style sheet.