如何在 Styled Component 中访问 Material-ui 的主题

How do I access Material-ui's theme in Styled Component

我将 CRA 与 Material-ui 和 Styled Components 类型的样式一起使用。 当创建我的 CSS 时,我想访问 Material-ui 的默认主题。

package.json的一部分:

  "dependencies": {
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-scripts": "3.0.1",
    "@material-ui/core": "^4.2.1",
    "@material-ui/icons": "^4.2.1",
    "@material-ui/styles": "^4.2.1",
    "styled-components": "^4.3.2"
  }

当我尝试下面的 theme 存在于 props 但它是一个空对象时。

StyledApp.js:

import styled from "styled-components";
import Button from "@material-ui/core/Button";

export const StyledButtonUsingTheme = styled(Button)`
  //Below will give "Cannot read property 'error' of undefined" 
  background-color: ${props => props.theme.palette.error.light};
`;

App.js:

import React from "react";
import "./App.css";

import { StylesProvider, ThemeProvider } from "@material-ui/styles";
import { createMuiTheme } from "@material-ui/core/styles";

import { StyledButtonUsingTheme } from "./StyledApp";

function App() {
  const defaultTheme = createMuiTheme();

  window.console.log("Default theme passing to ThemeProvider", defaultTheme);

  return (
    <StylesProvider injectFirst>
      <ThemeProvider theme={defaultTheme}>
        <div className="App">
          <StyledButtonUsingTheme variant="outlined">
            Styled Button Using Theme
          </StyledButtonUsingTheme>
        </div>
      </ThemeProvider>
    </StylesProvider>
  );
}

export default App;

App.js 中的 console.log 显示了整个主题对象,这就是我传递给 ThemesProvider 的内容。有趣的是 props.theme 在那里!但遗憾的是没有价值观。

问题已解决!

解决方案是使用: import { ThemeProvider } from "styled-components"; 在 App.js 然后 themeprops 对象上的所有值都在那里。

我在 App.js 中使用了来自“@material-ui/styles”的 ThemeProvider import { StylesProvider, ThemeProvider } from "@material-ui/styles"; 这与在 StyledApp.js

中从 "styled-components" 导入样式效果不佳

工作的两个文件:

App.js

import React from "react";
import "./App.css";

import { StylesProvider } from "@material-ui/styles";
import { ThemeProvider } from "styled-components";
import { createMuiTheme } from "@material-ui/core/styles";

import { StyledButtonUsingTheme } from "./StyledApp";

function App() {
  const defaultTheme = createMuiTheme();

  window.console.log("Default theme passing to ThemeProvider", defaultTheme);

  return (
    <StylesProvider injectFirst>
      <ThemeProvider theme={defaultTheme}>
        <div className="App">
          <StyledButtonUsingTheme variant="outlined">
            Styled Button Using Theme
          </StyledButtonUsingTheme>
        </div>
      </ThemeProvider>
    </StylesProvider>
  );
}

export default App;

样式化App.js

import styled from "styled-components";
import Button from "@material-ui/core/Button";

export const StyledButtonUsingTheme = styled(Button)`
  //Below will work now!
  background-color: ${props => props.theme.palette.error.light};
`;

正如 Horyd 在评论中所说,使用 Styled-Components 中的 ThemeProvider 将使您能够访问样式化组件中的主题属性。 但是 Material-UI 不再将该主题应用于它自己的组件。

我发现的解决方法既简单又丑陋:同时使用 Themeproviders。因此 Material-UI 将主题应用于其组件,您可以在样式化的组件中访问主题。

import { ThemeProvider } from "styled-components";
import { MuiThemeProvider,StylesProvider } from "@material-ui/core/styles";

ReactDOM.render(

  //Make sure the Material stylesheet is placed above your own 
  //styles so you can overwrite them
  <StylesProvider injectFirst> 

    //Use the theme in the ThemeProvider for Material-UI so
    //styles are applied to the Material-UI components
    <MuiThemeProvider theme={theme}>

      //Use also the ThemeProvider for Styled-Components so 
      //you can access the theme in your own css
      <ThemeProvider theme={theme}>

        //Include your app and you have acces to everything 
        <App />

      </ThemeProvider>

    </MuiThemeProvider>

  </StylesProvider>,

document.getElementById("app"));

你可以使用 withTheme :

App.js

import React from "react"
import { ThemeProvider, createMuiTheme } from "@material-ui/core/styles"
import { StyledButton } from "./StyledButton"

const App = () => {

    const theme = createMuiTheme();

    return (
        <ThemeProvider theme={theme}>
            <StyledButton />
        </ThemeProvider>
    )
}

export default App

StyledButton.js

import { styled, withTheme } from "@material-ui/core/styles"
import Button from "@material-ui/core/Button"

export const StyledButton= styled(withTheme(Button))(props => ({
  background: props.theme.palette.background.paper,
}))

使用withTheme的答案基本完成了。最后一部分对我不起作用,所以我改为:

import styled from 'styled-components'
import { withTheme } from "@material-ui/core/styles"

const StyledButton = withTheme(styled('h1')`
    background-color: ${props => props.theme.palette.error.light};
  `
)

如果你想使用两个 ThemeProvider,第一个来自 styled-components,第二个来自 material-ui,你可以使用 alias 作为其中之一他们:

import { ThemeProvider as StyledThemeProvider} from 'styled-components';
import { ThemeProvider } from '@material-ui/core/styles';

 function App() {
  return (
    <Router>
      <ThemeProvider theme={theme}>
      <StyledThemeProvider theme={theme}>
        <Wrapper>
          <TheHeader />
          <TheContent />
          <TheFooter />
        </Wrapper>
      </StyledThemeProvider>
      </ThemeProvider>
    </Router >
  );
}

export default App;

在您的样式组件中,您可以使用挂钩 useTheme 示例:

import { useTheme } from "@material-ui/core"
import { styled } from "@material-ui/styles"

const theme = useTheme

  const StyledListbox = styled("ul")({
    backgroundColor: theme.palette.primary.main,
  })

在我的例子中,我发现 theme 对象是通过 styled component 自动传入的,并且可以通过参数访问,如下所示:

import React from 'react';
import { styled } from '@material-ui/core';

const StyledButton = styled('button')(({ theme }) => ({
    color: theme.palette.text.secondary,
}));

我在 MUI v4.11.0 中使用此功能。

对于 MUI v5:

index.tsx

import { ThemeProvider, createTheme } from "@mui/material/styles";
import { StyledEngineProvider} from "@mui/material";
import { ThemeProvider as ScThemeProvider } from "styled-components";

import App from "components/App/App";

const theme = createTheme();

ReactDOM.render(
  <StyledEngineProvider injectFirst>
    <ThemeProvider theme={theme}>
      <ScThemeProvider theme={theme}>
        <App />
      </ScThemeProvider>
    </ThemeProvider>
  </StyledEngineProvider>,
  document.getElementById("root")
);

我在 MUI v5 中是这样做的

import { styled as muiStyled } from '@mui/material';

const NavLinkStyle = muiStyled('div')(({ theme }) => ({
  padding: '0 10px',
  height: '100%',
  fontWeight: 'bold',
  '&:hover': {
    color: theme.palette.primary.main,
    cursor: 'pointer',
    borderRadius: '15px'
  }
}));