Reputation: 290
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;
Upvotes: 0
Views: 925
Reputation: 290
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',
},
// ...
}));
Upvotes: 0
Reputation: 2252
From the explanation of the problem you described I believe if you wrap your application in the ThemeProvider you should be able to do it only in the parent App component and all you children will have access to the theme.
For example
import { ThemeProvider } from '@mui/material/styles';
import { theme } from './Theme'; // This is where I have my theme, change with yours please
function App() {
return (
<Router>
<ThemeProvider theme={theme}> // Here is where I wrap all my pages and the children components can have access to the theme
<Routes>
<Route path={HOME_PAGE} element={<Home />} />
<Route path={ABOUT_PAGE} element={<About />} />
</Routes>
</ThemeProvider>
</Router>
);
}
Here is my Theme file.
import { createTheme } from '@mui/material/styles';
export const theme = createTheme({
palette: {
primary: {
main: '#2d9cdb',
dark: '#2e85d4',
},
secondary: {
main: '#2e85d4',
},
text: {
primary: '#000000',
secondary: '#2d9cdb',
},
...
},
components: {
MuiAlert: {
styleOverrides: {
standardSuccess: {
backgroundColor: '#55ab68',
color: '#FFFFFF',
fontWeight: 'bold',
},
standardError: {
backgroundColor: '#ed4a3a',
color: '#FFFFFF',
fontWeight: 'bold',
},
}
}
}
});
Then for example inside my home page i have an Alert component that uses the theme.
<Alert severity="error" icon={false}>
<Typography variant="h4" color="secondary" align="center" >
Test text
</Typography>
</Alert>
Please let me know if it helped.
Upvotes: 2