Ashutosh
Ashutosh

Reputation: 588

How to access material theme in shared component in react?

I have two react projects Parent and Common project (contains common component like header, footer)

I have material theme defined in Parent and configured in standard way using MuiThemeProvider.

However, this theme object is available inside components defined in Parent, but not in share project common.

Suggestions are appreciated.

Added below more details on Oct 30, 2020

Parent Component

import React from "react";
import "./App.css";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import themeDefault from "./CustomTheme.js";
import { MuiThemeProvider } from "@material-ui/core/styles";
import { createMuiTheme } from "@material-ui/core/styles";
import Dashboard from "./containers/Dashboard/Dashboard";
import { Footer, Header } from "my-common-react-project";

function App() {
  const routes = () => {
    return (
      <BrowserRouter>
        <Switch>
          <Route exact path="/" component={Dashboard} />
        </Switch>
      </BrowserRouter>
    );
  };
  return (
    <MuiThemeProvider theme={createMuiTheme(themeDefault)}>
      <div className="App">
        <Header
          logo="some-logo"
          userEmail={"test@email"}
        />
        ... app components here..
        <Footer />
      </div>
    </MuiThemeProvider>
  );
}

export default App;

Shared component

import React from "react";
import {
  Box,
  AppBar,
  Toolbar,
  Typography,
} from "@material-ui/core/";

import styles from "./Header.styles";
import PropTypes from "prop-types";

const Header = (props) => {
  const classes = styles();
  const { options, history } = props;
  const [anchorEl, setAnchorEl] = React.useState(null);
  const handleCloseMenu = () => {
    setAnchorEl(null);
  };

  const goto = (url) => {
    history.push(url);
  };
  return (
    <Box component="nav" className={classes.headerBox}>
      <AppBar position="static" className={classes.headerPart}>
        <Toolbar className={classes.toolBar}>
          {localStorage && localStorage.getItem("isLoggedIn") && (
            <>
              {options &&
                options.map((option) => (
                  <Typography
                    key={option.url}
                    variant="subtitle1"
                    className={classes.headerLinks}
                    onClick={() => goto(option.url)}
                  >
                    {option.name}
                  </Typography>
                ))}
            </>
          )}
        </Toolbar>
      </AppBar>
    </Box>
  );
};

Header.propTypes = {
  options: PropTypes.array
};
export default Header;

Shared Component style

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

export default makeStyles((theme) => ({
  headerPart: {
    background: "white",
    boxShadow: "0px 4px 15px #00000029",
    opacity: 1,
    background: `8px solid ${theme.palette.primary.main}`
    borderTop: `8px solid ${theme.palette.primary.main}`
  }
}));

The Parent component defined theme.palette.primary.main as say Red color and I expect same to be applied in Header but it is picking a different theme (default) object which has theme.palette.primary.main blue.

Which results in my header to be in blue color but body in read color.

Any suggestion how to configure this theme object so that header too picks the theme.palette.primary.main from parent theme object.

Upvotes: 3

Views: 2001

Answers (2)

TOPKAT
TOPKAT

Reputation: 8658

here is the answer for mui V5

import { useTheme } from '@mui/material/styles' // /!\ I fixed a typo from official doc here

function DeepChild() {
  const theme = useTheme();
  return <span>{`spacing ${theme.spacing}`}</span>;
}

Taken from mui documentation

Upvotes: 1

NearHuscarl
NearHuscarl

Reputation: 81340

You can use either useTheme or withTheme to inject the theme object to any nested components inside ThemeProvider.

  • Use useTheme hook in functional components
  • Use withTheme HOC in class-based components (which can't use hook)
function DeepChild() {
  const theme = useTheme<MyTheme>();

  return <span>{`spacing ${theme.spacing}`}</span>;
}

class DeepChildClass extends React.Component {
  render() {
    const { theme } = this.props;
    return <span>{`spacing ${theme.spacing}`}</span>;
  }
}

const ThemedDeepChildClass = withTheme(DeepChildClass);

Live Demo

Edit Material demo (forked)

Upvotes: 0

Related Questions