Search code examples
reactjsmaterial-uimigrationemotionjss

material v5 migration: migrate from JSS to Emotion


I'm trying to migrate my material-ui project from JSS to Emotion in order to support react18. I ran the

npx @mui/codemod v5.0.0/jss-to-styled <path>

command successfully. However, when I try to run my app, I have the following error on all child components but not on the root parent component where theme is defined:

Uncaught ReferenceError: theme is not defined

I can pass theme as a prop to the child components, however the part of the code where i need theme is outside the scope of the component. So, this doesn't fix the issue. Additionally, this error doesn't occur on the parent root component because that's where theme variable is defined:

declare module '@mui/styles/defaultTheme' {
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
  interface DefaultTheme extends Theme {}
}
const theme = createTheme(adaptV4Theme({}));

Thus, if I add the code above in all components, I don't have this error anymore and it fixes the issue. Having said that, I think this is not the correct approach.

Does anyone have any better suggestion? Thank you!

[EDIT] Here's what my code looks like:

export default function App() {
  return (
    <Router>
      <ThemeProvider theme={theme}>
        <Routes>
          <Route path="/" element={<Home />} />
        </Routes>
      </ThemeProvider>
    </Router>
  );
}

This works for the Home react function component, however it doesn't work for its children components :(

[EDIT 2] Here's an example of a child component:

import React, { useState, useEffect } from 'react';
import { styled } from '@mui/material/styles';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline';
import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Link from '@mui/material/Link';
import Grid from '@mui/material/Grid';
import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress';
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
import Typography from '@mui/material/Typography';
import Container from '@mui/material/Container';

const PREFIX = 'LogIn';

const classes = {
  paper: `${PREFIX}-paper`,
  background: `${PREFIX}-background`,
  avatar: `${PREFIX}-avatar`,
  form: `${PREFIX}-form`,
  submit: `${PREFIX}-submit`
};

const StyledContainer = styled(Container)((
  {
    theme
  }
) => ({
  [`& .${classes.paper}`]: {
    marginTop: theme.spacing(8),
    padding: theme.spacing(4),
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    backgroundColor: theme.palette.background.paper,
  },

  [`&.${classes.background}`]: {
    display: 'flex',
    alignItems: 'center',
    background:
      'linear-gradient(200.96deg, #ffd194 -29.09%, #4DBD90 51.77%, #062627 129.35%) no-repeat center center fixed',
    position: 'absolute',
    top: '0px',
    right: '0px',
    bottom: '0px',
    left: '0px',
    margin: '0',
    height: '100vh',
    minWidth: '100vw',
    zIndex: '2',
  },

  [`& .${classes.avatar}`]: {
    margin: theme.spacing(1),
    backgroundColor: '#151d29',
    width: 56,
    height: 56,
  },

  [`& .${classes.form}`]: {
    width: '100%', // Fix IE 11 issue.
    marginTop: theme.spacing(1),
  },

  [`& .${classes.submit}`]: {
    margin: theme.spacing(3, 0, 2),
  }
}));
export const LogIn: React.FC<{ onLogin: Function, onSignup: Function }> = ({ onLogin, onSignup }) => {
...
return (
    <StyledContainer className={classes.background}>
      <Container component="main" maxWidth="xs" sx={{ zIndex: 3 }}>
        <CssBaseline />
        <div className={classes.paper}>
        ...
    );
}
export default LogIn;

Solution

  • I found the issue! I added theme as an argument to the arrow function and it is working - which makes sense. How it was:

    const Root = styled('div')(() => ({
      [`& .${classes.chartParent}`]: {
        height: '160px',
      },
      // ... 
    }));
    

    Fixed code:

    const Root = styled('div')(({theme}) => ({
      [`& .${classes.chartParent}`]: {
        height: '160px',
      },
      // ... 
    }));