Material-ui: makeStyles, withTheme and useTheme not working

Created on 5 Feb 2019  路  29Comments  路  Source: mui-org/material-ui


I'm trying to use the sample code for an app bar provided in the documentation (note that I'm not using the AppBar component- I have my own header component. But I'm currently trying to create a SearchField component based on this code). I've basically cut and pasted the code as-is, and pulled out the parts not related to the search field. I'm getting an error: Uncaught TypeError: Cannot read property 'borderRadius' of undefined. Digging into it, I see that the theme object being passed into the function I pass into makeStyles is an empty object. I investigated further, to see if I could get my hands on the theme. When I export my component with withTheme()(searchBar), the theme object in the props is null. Likewise, if I just call useTheme() in my component, it also returns null.

Note: it seems the plain JS sample code (no hooks) works - so this has something to do with the Material-UI and React 16.8.0-alpha.1. However- this version is required to use the sample hooks code.

  • [X] This is not a v0.x issue.
  • [X] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior 馃


My makeStyles function should be passed the populated theme object, and withTheme and useTheme should return the proper non-null theme object.

Current Behavior 馃槸


The theme object passed into makeStyles is empty. The theme props attribute injected by withTheme is null. The theme object returned by useTheme is null.

Steps to Reproduce 馃暪


Link: I don't have a live link but it's easy to reproduce:

  1. create-react-app testy
  2. cd testy
  3. Modify package.json, setting the react and react-dom versions to ^16.8.0-alpha.1 (to make use of hooks)
    "react": "^16.8.0-alpha.1",
    "react-dom": "^16.8.0-alpha.1",
  1. npm install (to update react)
  2. npm install --save @material-ui/core @material-ui/styles @material-ui/icons
  3. Copy the Hooks version of the Sample App Bar with a primary search field
  4. Paste this code into the test app's /src/App.js file (overwrite the existing code) and save
  5. npm start - you will get an undefined error when the makeStyles function accesses the empty theme object

Context 馃敠


I'm trying to implement a toolbar in my app with Material-UI.

Your Environment 馃寧

| Tech | Version |
|--------------|---------|
| Material-UI | v3.9.2 |
| React | 16.8.0-alpha.1 |
| Browser | Chrome 71.0 |
| TypeScript | 3.3.0-rc |
| etc. | |

bug 馃悰 docs important

Most helpful comment

@joshwooding figured it out. the import "./bootstrap"; must be the very top import of the index.js. i.e.

import "./bootstrap";
import React from "react";
import ReactDOM from "react-dom";
import App from "./app";

instead of

import React from "react";
import ReactDOM from "react-dom";
import App from "./app";
import "./bootstrap";

Thank you for your help.

All 29 comments

@ericsolberg This probably broke in #13229.

Be sure to follow https://material-ui.com/css-in-js/basics/#migration-for-material-ui-core-users in your own code.

@ericsolberg @material-ui/styles styling solution is standalone, it doesn't know anything about Material-UI components. You need to use the ThemeProvider from the style package with the const theme = createMuiTheme() function from the core package. You have an example here: https://github.com/mui-org/material-ui/tree/next/examples/nextjs-hooks.

This is exactly the type of frustration that working on v4 enable us to fix. I can think of the following possible approaches:

  • wrap the @material-ui/styles modules in @material-ui/core/styles to provide the default theme. Update the demos to reflect this change.
  • work on the DX by adding a warning. At least people will know, right from their console, the necessary steps.

@eps1lon I don't think that #13229 is linked.

@oliviertassinari It broke the dependencies in the codesandbox for hooks version. This shouldn't be an issue once stable react with hooks is released (which should've been yesterday).

Oh, so there are multiple problems :).

wrap the @material-ui/styles modules in @material-ui/core/styles to provide the default theme.

would this mean const useStyles = makeStyles(theme => ({ would pass the global theme variable without a ThemeProvider? If so, great! I'm not happy to wrap hundreds of components with (yet another) provider just to access the theme.

@ericsolberg I'm new to both ts and mui so don't really know what I'm doing, but what worked for me was:

import { Theme } from '@material-ui/core/styles/createMuiTheme';
...
const theme = useTheme<Theme>();

(using createMuiTheme and Theme from @material-ui/core/styles and all else from @material-ui/styles)

I have a similar issue and I'm not sure to understand what I did wrong.
The "red" primary color is not used anymore.

Before

import { createMuiTheme, MuiThemeProvider } from '@material-ui/core/styles';

const theme = createMuiTheme({
  palette: {
    primary: red,
  },
});

export default <MuiThemeProvider theme={theme}>
...
<MuiThemeProvider />

After

import { createMuiTheme } from '@material-ui/core/styles';
import { ThemeProvider } from '@material-ui/styles';

const theme = createMuiTheme({
  palette: {
    primary: red,
  },
});

export default <ThemeProvider theme={theme}>
...
<ThemeProvider />

Before

const NavBar = ({ classes }: WithStyle<ClassKey>): ReactElement => {
  return (
    <AppBar position="fixed" className={classes.appBar}>
      <Toolbar>
        <Typography color="inherit" variant="h6">
          App
        </Typography>
      </Toolbar>
    </AppBar>
  );
};

type ClassKey = 'appBar' | 'toolbar';

const styles = (theme: Theme): StyleRules<{}, ClassKey> => ({
    appBar: {
      zIndex: theme.zIndex.drawer + 1,
    },
    toolbar: theme.mixins.toolbar,
  }),
);

export default withStyles(styles)(NavBar)

After

const NavBar = (): ReactElement => {
  const classes = useStyles();

  return (
    <AppBar position="fixed" className={classes.appBar}>
      <Toolbar>
        <Typography color="inherit" variant="h6">
          App
        </Typography>
      </Toolbar>
    </AppBar>
  );
};

type ClassKey = 'appBar' | 'toolbar';

const useStyles = makeStyles(
  (theme: Theme): StyleRules<{}, ClassKey> => ({
    appBar: {
      zIndex: theme.zIndex.drawer + 1,
    },
    toolbar: theme.mixins.toolbar,
  }),
);

export default NavBar

@VincentLanglet Are you performing the bootstrap step? https://material-ui.com/css-in-js/basics/#migration-for-material-ui-core-users

Hey folks, thanks for your work on this project. I am having the exact same issue. With ThemeProvider the theme doesn't seem to be applied. I am definitely doing the bootstrap step.

With MuiThemeProvider the theme is applied but the makeStyles function does not get the Theme object. makeStyles does get it with ThemeProvider.

@MrStafford makeStyles is part of @material-ui/styles, therefore it is only intended to work with the ThemeProvider.

@joshwooding yep :). I was explaining my situation, I should have been more clear. I think the specific problem is with ThemeProvider not applying the theme whereas if I use MuiThemeProvider it works fine.

This is with the following dependencies:
"@material-ui/core": "^4.0.0-alpha.2",
"@material-ui/icons": "^4.0.0-alpha.1",
"@material-ui/styles": "^4.0.0-alpha.2",
"jss": "^10.0.0-alpha.12",

The code is pretty simple:

<StylesProvider jss={myJss} generateClassName={generateClassName}> 
    <ThemeProvider theme={myTheme}>
        <CssBaseline />
        <MyPage />
    </ThemeProvider>
</StylesProvider>

@MrStafford Do you have a reproduction I can have a look at?

@joshwooding I believe the following codesandbox displays the issue. If you change ThemeProvider to MuiThemeProvider it will change the background color to dark.

https://codesandbox.io/s/q9lmro76y4?fontsize=14

Actually. Really strangely it was showing the issue when I created it. Now it is working. I'll try to see the difference between it and my project.

@MrStafford When I view your codesandbox I get the dark background straight away (using the ThemeProvider)

@joshwooding you are right. When I remove, save and then re-add import "./bootstrap"; it breaks again.

@joshwooding figured it out. the import "./bootstrap"; must be the very top import of the index.js. i.e.

import "./bootstrap";
import React from "react";
import ReactDOM from "react-dom";
import App from "./app";

instead of

import React from "react";
import ReactDOM from "react-dom";
import App from "./app";
import "./bootstrap";

Thank you for your help.

@MrStafford Your bootstrap is being imported after your App, it should be before

Looks like you beat me to it :)

import React from "react";
import ReactDOM from "react-dom";
import "./bootstrap";
import App from "./app";

will work as well

it is a human error of appreciation

correct way

import { ThemeProvider } from '@material-ui/styles';
import { createMuiTheme } from '@material-ui/core/styles';

wrong way

dont use like this "import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';"

error is related to a typeof but sounds like a package error: Attempted import error: 'ThemeProvider' is not exported from '@material-ui/core/styles'.

dont use like this "import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';"

You can use imports "like this". Just import the correct names (ThemeProvider -> MuiThemeProvider).

I just wasted a few hours on figuring out why my theme wasn't being applied... hopefully this comment helps someone:

This compiles and auto-completes in my IDE using typescript, but definitely does not work:

import ThemeProvider from "@material-ui/styles/ThemeProvider/ThemeProvider";

It should just be:

import {ThemeProvider} from "@material-ui/styles";

@lookfirst What's your IDE? Do you have a way to configure it, to get the correct import?

IDEA. Sure, you can pick the right import from the list, but I picked the wrong one because I've been badly trained in the past to pull the most 'complete' import so that tree shaking would work better. Yes, I know that is moot these days, but whatever... Would be nice if MUI had a more restricted set of exports so that stuff like this didn't get picked up by accident.

@lookfirst I can't find any way to configure the auto-import from our side. Tree-shaking should work with the latest version of Material-UI. You should also be able to leverage https://material-ui.com/guides/minimizing-bundle-size/#option-2 for better perf in dev mode.

@oliviertassinari

Control the exports. Google Firebase client (not admin) SDK has some crazy crazy stuff going on in that department if you want to look into it.

Since option 2 is the 'best UX/DX', shouldn't it be noted as option 1? =) Also, I'm using CRA, so updating the instructions to make sure that usecase is covered seems like a wise option given the ubiquity of that solution. That said, from what I can tell, it just magically works. But you're more of an expert than I on this matter... so best to double check.

@lookfirst It does work, but its 10-30% slower to start your dev server. Yeah CRA is a challenge. It requires the usage of another dependency. I can't find any material on the auto import work Firebase has done. Do you have a link to share?

@oliviertassinari
Ah, yea I've noticed starting up dev is pretty slow. I guess that must be it. Doh.

In the above link, you mention: "Pick one of the following plugins:" for the babel option two. Just some feedback, it would be nice to know the differences between those two options. Why should I pick one plugin over the other? The confusing morass of TS / JS / Babel / CRA / etc... makes it an endless rabbit hole and any little extra bit of information there helps a lot. Thanks!

Here is the info on firebase:

https://firebase.google.com/docs/web/setup
npm install --save firebase

Then try clicking through to see the tricks they employ with typescript/npm/package.json.

It seems that they have inlined everything at the root: https://unpkg.com/browse/[email protected]/index.d.ts.

@oliviertassinari Ah yes, but dig a little deeper:

https://unpkg.com/browse/[email protected]/app/package.json
https://unpkg.com/browse/[email protected]/app/dist/index.esm.js

They push all the 'code' into @firebase/app... this way you can't accidentally import from there.

Thanks for the details. It's an interesting approach. We should consider having a flat file for each folder, maybe it's actually better than what we do now.

Was this page helpful?
0 / 5 - 0 ratings