【问题标题】:How to implement a theme switcher on an existing React site如何在现有的 React 站点上实现主题切换器
【发布时间】:2021-07-14 15:42:02
【问题描述】:

我目前有两个主题文件,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.jstheme-dark.js 之间切换时遇到了一些问题。如果有人可以推动我朝着正确的方向前进,我将不胜感激。不幸的是,由于我公司的安全原因,这是我可以粘贴的所有实际代码,但我认为这里的主要问题是index.js 中的&lt;Provider&gt; 元素在提供自定义主题提供程序时会中断。

【问题讨论】:

  • 您作为道具传递的theme 也是theme.js 文件吗?如果是,您想根据一些切换将其更改为theme-dark
  • @BadalSaibo 是的,themetheme.js 文件。目标是根据用户单击切换器或网站上的某些输入将其更改为 theme-dark 文件。
  • 那么除了切换之外,您当前的实现是否正常工作?另外,“当提供自定义主题提供程序时,index.js 中的 元素会中断”是什么意思。
  • @BadalSaibo 我当前的实现有效-theme 道具正确地通过了正常的theme.js 文件,如果我将theme 道具初始化更改为引用theme-dark.js,它会显示主题正确。我使用this 指南作为实现主题切换器的基础,当我进入必须将CustomThemeProvider 组件添加到index.js 的步骤时,当CustomThemeProvider 嵌套在&lt;Provider&gt; 标签。我会尝试重新创建特定的错误。

标签: css reactjs material-ui themes


【解决方案1】:

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

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

为您的主题类型创建一个 reducer,

// 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 以进行持久化,您可以按照docs 中的说明轻松完成。

【讨论】:

  • 您好,非常感谢您的帮助。这个解决方案几乎对我有用,但问题是我没有rootReducer.js 文件。我的combineReducers 函数位于/src/redux/reducers/index.tsx. 我仍然可以将isDarkModeReducer 添加到combineReducers 函数中,但是在执行下一步并在App.tsx 中添加useSelector 时,我遇到了以下错误:@987654340 @ 指向该行代码的state.isDarkMode 部分中的isDarkMode。
  • 没关系,我能够使用this previous solution 并使用useAppDispatchuseAppSelector 而不是useDispatchuseSelector 来解决这个问题。再次感谢您的帮助!
  • 那是类型错误。您需要将 isDarkMode 属性添加到 DefaultRootState 类型。我很高兴你仍然设法解决了问题。
猜你喜欢
  • 2021-01-31
  • 1970-01-01
  • 1970-01-01
  • 2020-09-02
  • 2015-09-28
  • 2021-09-10
  • 1970-01-01
  • 2018-03-16
  • 2023-03-26
相关资源
最近更新 更多