首页 > 解决方案 > 如何在现有的 React 站点上实现主题切换器

问题描述

我目前有两个主题文件,theme.jstheme-dark.js. 我还有一个已经设置好的基于 React 的复杂站点,我找不到一种方法来实现用户通过站点上的某些切换器在两个主题文件之间切换的方法。

这是我的index.js渲染函数的样子:

const rootElement = document.getElementById('root')
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
)

这就是App.tsx文件中的相关代码的样子:

<ThemeProvider theme={theme}>
     <CssBaseline />
     <SnackbarProvider
          .....
     </SnackbarProvider>
</ThemeProvider>

文件中的上述代码App.tsx嵌套在一些自定义上下文提供程序组件中,并包含一些用于加载站点初始组件的数据。

我在使用现有代码实现主题切换器以在theme.js和之间切换时遇到了一些麻烦theme-dark.js。如果有人能给我推动正确的方向,我将不胜感激。不幸的是,由于我公司的安全原因,这是关于我可以粘贴的所有实际代码,但我认为这里的主要问题是提供自定义主题提供程序时<Provider>元素中断。index.js

标签: cssreactjsmaterial-uithemes

解决方案


一个简单的状态就足够了,但您可能需要在应用程序的深处切换状态,即开关/按钮所在的位置。

你可以通过 Context,但既然你已经在使用 redux,为什么要重新发明轮子。

为您的主题类型创建一个减速器,

// isDarkModeReducer.js

export default function isDarkModeReducer(state = false, action) {
  switch (action.type) {
    case 'toggleDarkMode': {
      return !state;
    }

   default: 
    return state;
  }
}

将其添加到您的rootReducer

// rootReducer.js
...
import isDarkModeReducer from '<location of your isDarkModeReducer reducer>';
...
const rootReducer = combineReducers({
  ...
  isDarkMode: isDarkModeReducer
})
...

在您App.tsx访问isDarkMode创建的商店中的值时,并使用它有条件地传递theme.jstheme-dark.js归档。

// App.tsx
...
import theme from 'theme.js';
import theme-dark from 'theme-dark.js';
import { useSelector } from 'react-redux'

const isDarkMode = useSelector(state => state.isDarkMode);
...
return (
  <ThemeProvider theme={isDarkMode ? theme-dark : theme}>
     <CssBaseline />
     <SnackbarProvider
          .....
     </SnackbarProvider>
  </ThemeProvider>
);
...

对于切换,您所要做的就是从您的切换按钮所在的任何位置dispatch进行操作toggleDarkMode

// SwitchButton
import { useDispatch } from 'react-redux'

const dispatch = useDispatch();

const toggleTheme = () => {
  dispatch({ type: 'toggleDarkMode' });
};


return (
  <button onClick={toggleTheme}>Switch Theme</button>
);

您可能还希望将值保存到 localStorage 以进行持久化,您可以按照文档中的说明轻松执行此操作。


推荐阅读