Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React & Material-UI: Theme undefined in createStyles() with TypeScript

I'm learning React with TypeScript and using the Material UI framework for the frontend. I try to get the media queries working, but I got an error:

Uncaught TypeError: Cannot read property 'up' of undefined at styles (webpack-internal:///./app/components/navigation/Toolbar/index.tsx:59)

This is the corresponding code:

const styles = ({breakpoints}: Theme) => createStyles( {
    grow: {
        flexGrow: 1
    },
    menuButton: {
        marginLeft: -12,
        marginRight: 20
    },
    sectionDesktop: {
        display: 'none',
        [breakpoints.up('md')]: {
            display: 'flex'
        }
    },
    sectionMobile: {
        display: 'flex'
    },
})

The styles are passed to the component with:

export default withStyles(styles)(Toolbar)

I read that it is not required to create a custom theme as the default one will be passed automatically to the functions. However, the breakpoints property of theme is undefined which cause a blank page.

Thanks for your help

Edit

Here is the code of the component which will still produce the problem without any other components.

import * as React from 'react'
import {
    Theme
} from '@material-ui/core'
import {
    createStyles,
    WithStyles,
    withStyles
} from '@material-ui/styles'
// import Drawer from '../Drawer'

const styles = ({breakpoints}: Theme) => createStyles( {
    grow: {
        flexGrow: 1
    },
    menuButton: {
        marginLeft: -12,
        marginRight: 20
    },
    sectionDesktop: {
        display: 'none',
        [breakpoints.up('md')]: {
            display: 'flex'
        }
    },
    sectionMobile: {
        display: 'flex'
    },
})

namespace Toolbar {
    interface Props {
    }

    export interface State {
        isOpen : boolean
        mobileMoreAnchorEl? : EventTarget & HTMLElement
    }

    export type AllProps = Props & WithStyles<typeof styles>
}

class Toolbar extends React.Component<Toolbar.AllProps, Toolbar.State> {
    constructor(props: Toolbar.AllProps, context?: any) {
        super(props, context);
        this.state = { isOpen: false, mobileMoreAnchorEl: undefined}
    }

    render() {
        const { classes } = this.props
        // const { isOpen } = this.state

        return(
            <React.Fragment>
                <div className={classes.sectionDesktop}>
                    Hello
                </div>
                <div className={classes.sectionMobile}>
                    World
                </div>
            </React.Fragment>
        )
    }

}

export default withStyles(styles)(Toolbar)

The main.tsx (a.k.a index.js) looks like this:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createBrowserHistory } from 'history';
import { configureStore } from 'app/store';
import { Router } from 'react-router';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import { App } from './app';

// prepare store
const history = createBrowserHistory()
const store = configureStore()
const theme = createMuiTheme()

ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
      <MuiThemeProvider theme={theme} >
        <App />
      </MuiThemeProvider>
    </Router>
  </Provider>,
  document.getElementById('root')
);

So, adding MuiThemeProvider does not help.

like image 293
Denis Loh Avatar asked Dec 25 '18 21:12

Denis Loh


1 Answers

UPDATE

At the time when this answer was first written, @material-ui/styles was unstable. It is not anymore (as of v4), but it is still generally best to import from @material-ui/core/styles since the default theme will not be available when importing from @material-ui/styles.


You can read here that @material-ui/styles is unstable (alpha version).

You'll notice in my CodeSandbox that I am using:

import { withStyles, createStyles } from "@material-ui/core/styles";

instead of importing these from @material-ui/styles. When I use the same import as you, I am able to reproduce your problem.

Edit 82kp602xqj


UPDATE for v5

In v5, usage of makeStyles and withStyles is deprecated and they were removed from @material-ui/core and are only accessible via @material-ui/styles. In v5, makeStyles and withStyles do not have access to the theme unless you provide access via the ThemeProvider (and for that to work you should be using the latest v5 versions of both @material-ui/core and @material-ui/styles). Below is a working v5 example.

import React from "react";
import ReactDOM from "react-dom";
import { createTheme, ThemeProvider } from "@material-ui/core/styles";
import { withStyles } from "@material-ui/styles";
const styles = ({ breakpoints }) => ({
  grow: {
    flexGrow: 1
  },
  menuButton: {
    marginLeft: -12,
    marginRight: 20
  },
  sectionDesktop: {
    display: "none",
    [breakpoints.up("md")]: {
      display: "flex"
    }
  },
  sectionMobile: {
    display: "flex"
  }
});
const MyToolbar = (props) => {
  return (
    <>
      <div className={props.classes.sectionDesktop}>Section Desktop</div>
      {props.children}
      <div className={props.classes.sectionMobile}>Section Mobile</div>
    </>
  );
};
const theme = createTheme();
const StyledToolbar = withStyles(styles)(MyToolbar);
function App() {
  return (
    <ThemeProvider theme={theme}>
      <StyledToolbar>
        <div>Hello</div>
        <div>CodeSandbox</div>
      </StyledToolbar>
    </ThemeProvider>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Edit v5 withStyles

like image 93
Ryan Cogswell Avatar answered Nov 26 '22 12:11

Ryan Cogswell