Hot Module Replacement with MuiThemeProvider always errors
See original GitHub issue- I have searched the issues of this repository and believe that this is not a duplicate.
Possibly related: https://github.com/mui-org/material-ui/issues/8353 https://github.com/mui-org/material-ui/issues/8878
Expected Behavior
Whenever I change a value in my const styles = theme => ({…}) in Drawer (or anything else in the application), material-ui withStyles should not throw an error.
Current Behavior
Anytime I change a value in my styles definition (or anything for that matter), after a hot module replacement, the following error occurs. The UI still updates as expected, but the errors start stacking up.
Uncaught TypeError: Cannot read property 'refs' of undefined
at ProxyComponent.detach (withStyles.js:339)
at ProxyComponent.detach (createPrototypeProxy.js:44)
at ProxyComponent.<anonymous> (withStyles.js:251)
at commitCallbacks (react-dom.development.js:6155)
at commitLifeCycles (react-dom.development.js:8812)
at commitAllLifeCycles (react-dom.development.js:9967)
at HTMLUnknownElement.callCallback (react-dom.development.js:540)
at Object.invokeGuardedCallbackDev (react-dom.development.js:579)
at invokeGuardedCallback (react-dom.development.js:436)
at commitRoot (react-dom.development.js:10071)
react-dom.development.js:9769 The above error occurred in the <withStyles(ResponsiveDrawer)> component:
in withStyles(ResponsiveDrawer) (created by App)
in MuiThemeProvider (created by MuiThemeProviderWrapper)
in MuiThemeProviderWrapper (created by App)
in App
in Router (created by ConnectedRouter)
in ConnectedRouter
in Provider
in AppContainer
Cannot read property 'refs' of undefined
at ProxyComponent.detach (withStyles.js:339)
at ProxyComponent.detach (createPrototypeProxy.js:44)
at ProxyComponent.<anonymous> (withStyles.js:251)
at commitCallbacks (react-dom.development.js:6155)
at commitLifeCycles (react-dom.development.js:8812)
at commitAllLifeCycles (react-dom.development.js:9967)
at HTMLUnknownElement.callCallback (react-dom.development.js:540)
at Object.invokeGuardedCallbackDev (react-dom.development.js:579)
at invokeGuardedCallback (react-dom.development.js:436)
at commitRoot (react-dom.development.js:10071)
Steps to Reproduce (for bugs)
Unfortunately this is a HMR issue, and I can’t workup a codesandbox.io example. Here is my relevant setup (maybe I am doing something wrong?)
Steps
- Build / Run
- Modify any part of app under the hot.module.accept (styles, content, etc…)
- Error occurs but UI updates OK (the UI still updates fine - but the error is still thrown)
App.js
import React from 'react';
import ReactDOM from 'react-dom';
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
import purple from 'material-ui/colors/purple';
import blue from 'material-ui/colors/blue';
import green from 'material-ui/colors/green';
import red from 'material-ui/colors/red';
import Drawer from '../Drawer';
import DevTools from '../DevTools';
const theme = createMuiTheme({
palette: {
primary: green, // Purple and green play nicely together.
secondary: {
...green,
A400: '#00e677',
},
error: red,
},
overrides: {
MuiDrawer: {
docked: {
flex: '0 0 auto',
height: '100%'
}
}
}
});
class App extends React.Component {
render() {
return (
<MuiThemeProvider theme={theme}>
<Drawer />
</MuiThemeProvider>
);
}
}
export default App;
Drawer.js
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import Drawer from 'material-ui/Drawer';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import List from 'material-ui/List';
import Typography from 'material-ui/Typography';
import IconButton from 'material-ui/IconButton';
import Hidden from 'material-ui/Hidden';
import Divider from 'material-ui/Divider';
import MenuIcon from 'material-ui-icons/Menu';
import Grid from 'material-ui/Grid';
import Paper from 'material-ui/Paper';
import { mailFolderListItems, otherMailFolderListItems } from './tileData';
const drawerWidth = 240;
const styles = theme => ({
root: {
width: '100%',
marginTop: 4,
zIndex: 1,
height: '100%',
overflow: 'hidden',
},
appFrame: {
position: 'relative',
display: 'flex',
width: '100%',
height: '100%',
},
appBar: {
position: 'absolute',
marginLeft: drawerWidth,
[theme.breakpoints.up('md')]: {
width: `calc(100% - ${drawerWidth}px)`,
},
},
navIconHide: {
[theme.breakpoints.up('md')]: {
display: 'none',
},
},
drawerHeader: theme.mixins.toolbar,
drawerPaper: {
width: 250,
height: '100%',
[theme.breakpoints.up('md')]: {
width: drawerWidth,
position: 'relative',
height: '100%',
},
},
content: {
backgroundColor: theme.palette.background.default,
width: '100%',
padding: theme.spacing.unit * 3,
height: 'calc(100% - 56px)',
marginTop: 56,
[theme.breakpoints.up('sm')]: {
height: 'calc(100% - 64px)',
marginTop: 64,
},
},
gridRoot: {
flexGrow: 1
},
gridPaper: {
padding: theme.spacing.unit * 2,
height: '100%'
},
docked: {
height: '100%'
}
});
class ResponsiveDrawer extends React.Component {
state = {
mobileOpen: false,
};
handleDrawerToggle = () => {
this.setState({ mobileOpen: !this.state.mobileOpen });
};
render() {
const { classes, theme } = this.props;
const drawer = (
<div>
<div className={classes.drawerHeader} />
<Divider />
<List>{mailFolderListItems}</List>
<Divider />
<List>{otherMailFolderListItems}</List>
</div>
);
return (
<div className={classes.root}>
<div className={classes.appFrame}>
<AppBar className={classes.appBar}>
<Toolbar>
<IconButton
color="contrast"
aria-label="open drawer"
onClick={this.handleDrawerToggle}
className={classes.navIconHide}
>
<MenuIcon />
</IconButton>
<Typography type="title" color="inherit" noWrap>
Responsive drawer
</Typography>
</Toolbar>
</AppBar>
<Hidden mdUp>
<Drawer
type="temporary"
anchor={theme.direction === 'rtl' ? 'right' : 'left'}
open={this.state.mobileOpen}
classes={{
paper: classes.drawerPaper,
}}
onRequestClose={this.handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
>
{drawer}
</Drawer>
</Hidden>
<Hidden mdDown implementation="css">
<Drawer
type="permanent"
open
classes={{
docked: classes.docked,
paper: classes.drawerPaper,
}}
>
{drawer}
</Drawer>
</Hidden>
<main className={classes.content}>
<Grid container className={classes.gridRoot}>
<Grid item xs={12}>
<Grid container alignItems='stretch'>
<Grid item key={1}>
<Paper className={classes.gridPaper}>
{'Content 1'}
</Paper>
</Grid>
<Grid item key={2}>
<Paper className={classes.gridPaper}>
{'Content 2'}
</Paper>
</Grid>
<Grid item key={3}>
<Paper className={classes.gridPaper}>
{'Content 3'}
</Paper>
</Grid>
</Grid>
</Grid>
</Grid>
</main>
</div>
</div>
);
}
}
ResponsiveDrawer.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
};
export default withStyles(styles, { withTheme: true })(ResponsiveDrawer);
Context
If I remove MuiThemeProvider from App.js, all works as expected with the default theme.
Doing some debugging, it looks like this line, at some point returns undefined / null:
var sheetManagerTheme = sheetManager.get(theme) https://github.com/mui-org/material-ui/blob/023fee9092571e98814e64221015c6b669353fbe/src/styles/withStyles.js#L267
in the detach method.
Your Environment
Tech | Version |
---|---|
Material-UI | ^1.0.0-beta.21 |
React | 16.0.0 |
browser | Chrome latest |
Issue Analytics
- State:
- Created 6 years ago
- Comments:13 (1 by maintainers)
Top GitHub Comments
Using react hot loader v4 (possibly 3), I think this can be solved by moving the MuiThemeProvider one level up. eg
render( <MuiThemeProvider theme={theme}> <App /> </MuiThemeProvider>, document.getElementById('app'))
Then having <App /> be the hot reload root component.
I changed
to
in my component wrapped by
<MuiThemeProvider>
, and now I just get a warning.