Material UI 5 - the easiest way to migrate from makeStyles to emotion
Tags: material, react, emotion, migration
Published: 2021-09-16 08:38:24

Material UI version 5 has cool new stuff, and also many breaking changes. The migration tool is also amazing, but the style migration might not be that easy. Migrating a huge project could be a real pain.

Fortunately, there is a way to make a new, easy way to simply migrate the existing structure to emotion. Lets start:

## Styles Root

At first, don't forget to setup correctly the root styles, emotion's ThemeProvider should override the default Material designs:

```JS
import React from 'react';
import { ThemeProvider as MuiThemeProvider, StylesProvider } from '@material-ui/core/styles';
import { ThemeProvider } from '@emotion/react';

const theme = {
  background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
};

const App = () => (
  <StylesProvider injectFirst>
    <MuiThemeProvider theme={theme}>
      <ThemeProvider theme={theme}>
        // All my components
      </ThemeProvider>
    </MuiThemeProvider>
  </StylesProvider>
);

export default App;
```

## The custom hook

For the custom hook, we will make use of the framework agnostic `@emotion/css` library, that can generate and inject classes from objects. [More here](https://emotion.sh/docs/@emotion/css)

Then, lets make a custom hook, that can rebuild our makeStyles:

```JS
import { useMemo } from 'react';
import { css } from '@emotion/css';
import { useTheme } from '@emotion/react';

const useClasses = stylesElement => {
  const theme = useTheme();
  return useMemo(() => {
    const rawClasses = typeof stylesElement === 'function'
      ? stylesElement(theme)
      : stylesElement;
    const prepared = {};

    Object.entries(rawClasses).forEach(([key, value = {}]) => {
      prepared[key] = css(value);
    });

    return prepared;
  }, [stylesElement, theme]);
};

export default useClasses;

```

This component will receive a object or a function with the styles, and create corresponding classes.

Then the last Step is - rework:

The **old components**

```JS
// TODO: Unwrap the function from makeStyles and rename useStyles
const useStyles = makeStyles(theme => ({
  paper: {
    marginTop: theme.spacing(8),
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
  },
  ...
}));


const TheComponent = () => {
 const classes = useStyles(); // useStyles from Material UI
}

```

will become 

```JS
// TODO: Unwrap the object from makeStyles and rename useStyles
const styles = theme => ({
  paper: {
    marginTop: theme.spacing(8),
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
  },
  ...
});

const TheComponent = () => {
 const classes = useClasses(styles); // useStyles from custom hook
}

```

**You can try also with pure object of classes:**

The old component

```JS
// TODO: Unwrap the object from makeStyles and rename useStyles
const useStyles = makeStyles({
  paper: {
    marginTop: theme.spacing(8),
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
  },
  ...
});

const TheComponent = () => {
 const classes = useStyles(); // useStyles from Material UI
}
```

will become:

```JS
const styles = {
  paper: {
    marginTop: theme.spacing(8),
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
  },
  //...
};

const TheComponent = () => {
 const classes = useClasses(styles); // useStyles from custom hook
}
```

In summary:
1. We setup the ThemeProvider and StylesProvider in our root component
2. We create a custom hook useStyles
3. We get rid of the makeStyles and unwrap the styles from it
4. Rename useStyles e.g. to styles, because it is no more a hook
5. Replace useStyles call inside of the component with our useClasses hook, while we put the styles object/function as argument

And with just a little bit rework, we already use emotion :) 

With this approach, we managed to migrate a 2-years Project in 1 hour.

If this simple function is not enough for you, like you need to use nested objects in the classes, typescript, withStyles or more, you can take a look at [tss-react](https://www.npmjs.com/package/tss-react)

Best Regards
Anton Tonchev
JUST-SELL.online