首页 > 解决方案 > 从嵌套组件更改 MUI 主题

问题描述

我有以下组件结构:

App -> ThemeProvider -> MenuBar -> ThemeControls -> Switch and Autocomplete

我想使用开关更改为暗模式并使用自动完成更改原色。为此,我添加了以下自定义挂钩。

import {createMuiTheme} from "@material-ui/core";
import {useState} from "react";

/**
 *  Hook to change the theme
 *
 * @returns {Theme, () => setDarkMode}
 */
const useThemeBuilder = () => {    
   
    const [myTheme, setMyTheme] = useState({})

    console.log('myTheme:', myTheme);
    let theme = createMuiTheme(myTheme);
    console.log('theme:' , theme);

    return [theme, setMyTheme]
}

export default useThemeBuilder;

该钩子需要一个主题对象来覆盖默认对象createMuiTheme。主题对象和改变钩子状态的回调被暴露了!

这是该对象的外观示例:

{
    "palette": {
        "type": "light",
        "primary": {
            "50": "#ffebee",
            "100": "#ffcdd2",
            "200": "#ef9a9a",
            "300": "#e57373",
            "400": "#ef5350",
            "500": "#f44336",
            "600": "#e53935",
            "700": "#d32f2f",
            "800": "#c62828",
            "900": "#b71c1c",
            "A100": "#ff8a80",
            "A200": "#ff5252",
            "A400": "#ff1744",
            "A700": "#d50000"
        }
    }
}

我现在的问题是App.js不会重新渲染并且思想不会注入新主题。

这是我的app.js

import './App.css';
import React from 'react';
import {BrowserRouter as Router, Route, Switch,} from "react-router-dom";
import {MyComponent} from "./components/MyComponent";
import {ThemeProvider, useTheme} from "@material-ui/core/styles";
import {MenuBar} from "./components/MenuBar";
import {MyButtons} from "./components/MyButtons";
import {Home} from "./components/Home";
import {MyForms} from "./components/MyForms";
import {MyHookedForm} from "./components/MyHookedForm";
import {MyCarousel} from "./components/MyCarousel";
import useThemeBuilder from "./components/theme/theme";
import {CssBaseline} from "@material-ui/core";


function App() {

    const [theme] = useThemeBuilder();
    console.log('theme from App:', theme)

    return (
        <Router>
            <ThemeProvider theme={theme}>
                <CssBaseline/>
                <MenuBar/>
                <Switch>
                    <Route path="/colors">
                        <MyComponent/>
                    </Route>
                    <Route path="/buttons">
                        <MyButtons/>
                    </Route>
                    <Route path="/forms">
                        <MyForms/>
                    </Route>
                    <Route path="/hook-forms">
                        <MyHookedForm/>
                    </Route>
                    <Route path="/carousel">
                        <MyCarousel/>
                    </Route>
                    <Route path="/">
                        <Home/>
                    </Route>
                </Switch>

            </ThemeProvider>
        </Router>
    );
}


export default App;

标签: reactjsmaterial-ui

解决方案


你需要的是一个上下文。由于您使用的是 useState ,因此每个使用钩子的组件都有自己的主题和 setMyTheme 变量。您应该创建一个导出 setMyTheme 函数的上下文提供程序。

你可以做这样的事情

import './App.css';
import React from 'react';
import {BrowserRouter as Router, Route, Switch,} from "react-router-dom";
import {MyComponent} from "./components/MyComponent";
import {ThemeProvider, useTheme} from "@material-ui/core/styles";
import {MenuBar} from "./components/MenuBar";
import {MyButtons} from "./components/MyButtons";
import {Home} from "./components/Home";
import {MyForms} from "./components/MyForms";
import {MyHookedForm} from "./components/MyHookedForm";
import {MyCarousel} from "./components/MyCarousel";
import useThemeBuilder from "./components/theme/theme";
import {CssBaseline} from "@material-ui/core";

const ThemeContext = React.createContext({theme:{}});
export const useMyTheme = ()=>React.useContext(ThemeContext);

function App() {

    const [theme,setMyTheme] = useState({});
    console.log('theme from App:', theme)

    return (
<ThemeContext.Provider value={{theme,setMyTheme}}>
        <Router>
            <ThemeProvider theme={theme}>
                <CssBaseline/>
                <MenuBar/>
                <Switch>
                    <Route path="/colors">
                        <MyComponent/>
                    </Route>
                    <Route path="/buttons">
                        <MyButtons/>
                    </Route>
                    <Route path="/forms">
                        <MyForms/>
                    </Route>
                    <Route path="/hook-forms">
                        <MyHookedForm/>
                    </Route>
                    <Route path="/carousel">
                        <MyCarousel/>
                    </Route>
                    <Route path="/">
                        <Home/>
                    </Route>
                </Switch>

            </ThemeProvider>
        </Router>
<ThemeContext.Provider>
    );
}


export default App;

在你想要使用它的组件中你可以做

const {theme,setMyTheme} = useMyTheme();

推荐阅读