微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何从商店获取主题并在react-admin上切换应用主题?

如何解决如何从商店获取主题并在react-admin上切换应用主题?

反应管理员版本:3.8.4

我有一个react-admin应用,我正在尝试在浅色和深色主题之间切换。

在下面,您可以看到 Theme.js ,其中我导出了两个对象,这些对象具有文档中所述的主题替代。 (https://material-ui.com/pt/customization/default-theme/

export const darkTheme = {
palette: {
    type: 'dark'
},overrides: {
    MuiAppBar: {
        colorSecondary: {
            backgroundColor: '#424242',//'#1e4c9a',color: '#fff'
        },},MuiButton: {
        textPrimary: {
            color: '#fff',}
    },MuiTypography: {
        colorPrimary: {
            color: '#fff'
        }
    },MuiDrawer: {
        paper: {
            paddingTop: '20px'
        }
    },MuiFilledInput: {
        underline: {
            '&:after': {
                borderBottomColor: '#bf9f00'
            }
        }
    },MuiFormlabel: {
        root: {
            '&$focused': {
                color: '#bf9f00'
            }
        }
    },}
}

export const lightTheme = {
    palette: {
        type: 'light'
    },overrides: {
        MuiAppBar: {
            colorSecondary: {
                backgroundColor: '#2196f3',color: '#fff'
            },}

我也做了一个customreducer,如下所示,名为 ThemeReducer.js

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

import { darkTheme } from '../../layout/Theme'
const Theme = createMuiTheme(darkTheme)

export default (prevIoUsstate = Theme,action) => {
  if (action.type === 'SWITCH_THEME') {
    return action.theme;
  }
  return prevIoUsstate;
}

也可以通过操作(ThemeAction.js)来分配状态:

export const switchTheme = (theme) => {
  return {
    type: 'SWITCH_THEME',theme
  }
}

要设置自定义的Reducer,如文档中所述,我在<Admin>上设置了自定义的Reducer属性,如下所示:

import Theme from './store/reducers/themeReducer'


const App = () => {

  return (
    <div className="admin-body">

      <Admin
        customreducers={{ theme: Theme }}
        layout={Layout}
        authProvider={login}
        dataProvider={dataProvider}
        loginPage={LoginPage}
        locale="pt"
        customroutes={[
          <Route
            key="configuration"
            path="/configuration"
            title="Configurações"
            component={Configuration}
          />
        ]}
      > ...

要在主题之间切换并设置为商店,我正在使用此配置页:

import React from 'react'
import { useSelector,usedispatch } from 'react-redux';
import Button from '@material-ui/core/Button';
import { switchTheme } from '../../store/actions/themeAction';
import { darkTheme,lightTheme } from '../../layout/Theme'
import { createMuiTheme } from '@material-ui/core/styles';

import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import { Title } from 'react-admin';

import './styles.css'

const Configuration = () => {
  const dispatch = usedispatch();
  const theme = useSelector(state => state.theme);

  const mainClass = 'configPage'

  return (
    <Card>
      <Title title="Configurações" />
      <CardContent className={mainClass}>
        <div className="theme-label">
          <p className="text" >Selecione seu Tema: </p>
          <Button
            variant="contained"
            className={theme.palette.type === 'light' ? 'active' : ''}
            onClick={() => dispatch(switchTheme(createMuiTheme(lightTheme)))}
          >
            Claro
        </Button>
          <Button
            variant="contained"
            className={theme.palette.type === 'dark' ? 'active' : ''}
            onClick={() => dispatch(switchTheme(createMuiTheme(darkTheme)))}
          >
            Escuro
        </Button>
        </div>
      </CardContent>
    </Card>

  )
}

export default Configuration;

所有这些结构都工作正常,我的意思是全局状态主题正在正确更新,因此reducer正在获取被单击的主题并切换状态。

问题是,如文档所述,要更改主题,我们必须将新主题作为属性传递给标签<Admin>,例如:<Admin theme={theme}> </admin> 但是标签<Admin>设置在App.js中,并且redux上下文不在App之上,因此无法将全局主题状态纳入其中。

然后我的问题是如何使用我创建的全局主题状态作为应用程序主题传递。

我已经尝试过作为Layout的父级传递,如下所示,但是主题未反映在应用程序上。

Layout.js

const MyLayout = (props) => {
    const theme = useSelector(state => state.theme)
    return (
        <ThemeProvider theme={theme}>
            <Layout
                {...props}
                appBar={AppBar}
                sidebar={Sidebar}
                menu={Menu}
                notification={Notification}
            />
        </ThemeProvider>
    )
};

App.js

...
    import Layout from './layout'
    
    const App = () => {
    
      return (
        <div className="admin-body">
    
          <Admin
            customreducers={{ theme: Theme }}
            layout={Layout}
            authProvider={login}
            dataProvider={dataProvider}
            loginPage={LoginPage}
            locale="pt"
            customroutes={[
              <Route
                key="configuration"
                path="/configuration"
                title="Configurações"
                component={Configuration}
              />
            ]}
          >
...

感谢任何帮助。 问候

解决方法

我不知道您的要求,但是也许没有必要将主题存储在redux中吗?您可以使用使用react上下文api的解决方案,如下所示:

type ThemeState = {
    theme: 'light' | 'dark',setTheme(theme: 'light' | 'dark'): void,};

const StateContext = React.createContext<ThemeState>({
    theme: 'light',setTheme: () => {}
});

export const ThemeStateProvider = (props: { children: React.ReactNode }) => {

    const [theme,setTheme] = React.useState('light');

    return (

        <StateContext.Provider value={{
            theme,setTheme
        }}>
            {props.children}
        </StateContext.Provider>
    );
};

export const useThemeState = () => useContext(StateContext);

并像这样使用它:

// new root compontent that wraps App
const Root = () => (
    <ThemeStateProvider>
       <App />
    </ThemeStateProvider>
)
const App = () => {
    const {theme} = useThemeState();
   
    return <Admin theme={theme === 'light' ? lightTheme : darkTheme} ... />
}
const Configuration = () => {
    const {setTheme} = useThemeState();
   
    [...]

    return (
        [...]
        <Button onClick={() => setTheme('light')} />
        [...]
    );
}

希望对您有用!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。