【问题标题】:How do I access Material-ui's theme in Styled Component如何在样式化组件中访问 Material-ui 的主题
【发布时间】:2019-11-28 05:21:53
【问题描述】:

我将 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 在那里!但遗憾的是没有价值。

【问题讨论】:

  • 我有一个解决方法:在 StyledApp.js 中使用: background-color: ${props => createMuiTheme().palette.error.light}; ...但是每次我想使用主题时调用 createMuiTheme() 感觉就像是一种黑客攻击
  • 但是您不能以任何方式将theme 传递给StyledButtonUsingTheme。我不明白这是怎么回事
  • 我希望将主题添加到 的每个子组件中。它实际上已添加但为空。注意主题不是未定义的,它是一个空对象,它是从哪里来的?
  • 当心:你从错误的地方导入styledimport { styled } from '@material-ui/styles';

标签: reactjs material-ui styled-components


【解决方案1】:

您可以使用 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,
}))

【讨论】:

    【解决方案2】:

    正如 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"));
    

    【讨论】:

    • 对于 MUI v5,使用 ThemeProvider 代替 MuiThemeProviderStyledEngineProvider 代替 StylesProvider
    【解决方案3】:

    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};
      `
    )
    

    【讨论】:

      【解决方案4】:

      问题解决了!

      解决方案是使用: import { ThemeProvider } from "styled-components"; 在 App.js 中,然后 theme 包含 props 对象上的所有值。

      我在 App.js 中使用了来自“@material-ui/styles”的 ThemeProvider import { StylesProvider, ThemeProvider } from "@material-ui/styles"; 这与 StyledApp.js 中的 `import styled from "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;
      

      StyledApp.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};
      `;
      

      【讨论】:

      • 我不确定这是否真的解决了同时为使用styled 构造的样式化组件提供主题以及自动将主题应用于&lt;Button color="primary"&gt;Click me&lt;/Button&gt; 等material-ui 组件的问题。使用您的解决方案,第二个示例不符合主题
      【解决方案5】:

      如果您想同时使用 ThemeProviders,首先来自 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;
      

      【讨论】:

        【解决方案6】:

        在我的例子中,我发现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 中有这个工作。

        【讨论】:

        • 谢谢!这节省了我的精力,因为我有大量样式化的组件并且不想到处实现withTheme
        【解决方案7】:

        在您的样式组件中,您可以使用钩子 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,
          })
        

        【讨论】:

          猜你喜欢
          • 2021-07-17
          • 2019-12-30
          • 2018-05-13
          • 2021-05-23
          • 2020-05-08
          • 2021-01-08
          • 1970-01-01
          • 2020-07-26
          • 2023-03-23
          相关资源
          最近更新 更多