【发布时间】:2021-11-06 15:44:28
【问题描述】:
ReactJS 和 Redux-Toolkit 有点麻烦
我想要一个global state 换一个Theme Switcher。这样我就可以在 App.tsx 中围绕我的整个项目包装一个 Material-UI 主题。但我总是得到错误:Store does not have a valid reducer. Make sure the argument passed to combineReducers is an object whose values are reducers.
我的商店是这样配置的:
import { combineReducers, configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { TypedUseSelectorHook, useSelector } from 'react-redux';
import { applyMiddleware } from 'redux';
import { themeUiReducer } from './ui/themeSlice';
export const rootReducer = combineReducers({
data: combineReducers({
}),
ui: combineReducers({
theme: themeUiReducer
}),
});
export const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) => [...getDefaultMiddleware()],
});
export type RootState = ReturnType<typeof store.getState>
export const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
而我的 themeUIReducer 看起来像这样:
import { createEntityAdapter, createSlice, PayloadAction } from "@reduxjs/toolkit";
export interface IThemes {
themeMode: boolean | undefined,
useOs: boolean | undefined
}
const initialState: IThemes = {
themeMode: false,
useOs: false
}
const themeSlice = createSlice({
name: 'themeUI',
initialState: initialState,
reducers: {
setThemeMode: (state, action: PayloadAction<boolean | undefined>) => {
state.themeMode = action.payload;
},
setUseOs: (state, action: PayloadAction<boolean | undefined>) => {
state.useOs = action.payload;
},
},
extraReducers: {
}
})
export const { setThemeMode, setUseOs } = themeSlice.actions;
export const themeUiReducer = themeSlice.reducer;
我在其中分派 reducer 的 App.tsx 文件配置如下:
import React, { useCallback, useState } from 'react';
import './App.css';
import Layout from './components/Layout';
import { Route, Switch, Redirect, withRouter } from 'react-router-dom';
import { ThemeProvider, createTheme, useMediaQuery, CssBaseline } from '@mui/material';
import ThemeSwitcher from './theme/themeSwitcher';
import { useDispatch } from 'react-redux';
import { setThemeMode, setUseOs } from './store/ui/themeSlice';
function App() {
const dispatch = useDispatch();
// Get OS-level preference for dark mode
const prefersDarkMode: boolean | undefined = useMediaQuery("(prefers-color-scheme: dark)");
const [darkMode, setDarkMode] = useState<boolean | undefined>(prefersDarkMode);
const themeOption = (b: boolean) => (b ? "dark" : "light");
const theme = React.useMemo(
() =>
createTheme({
palette: {
mode: themeOption(darkMode!)
}
}),
[darkMode]
);
const toggleDarkMode = (checked: boolean | undefined) => {
if (checked === null)
setDarkMode(prefersDarkMode);
else setDarkMode(checked);
};
const dispatchTheme = useCallback(
(themeMode: boolean | undefined) => {
if(themeMode === null)
dispatch(setThemeMode(prefersDarkMode));
else
dispatch(setThemeMode(themeMode));
},
[dispatch]
);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<ThemeSwitcher useOs={false} themeChanger={dispatchTheme} />
<Layout>
<Switch>
<Route />
<Route />
<Route />
</Switch>
</Layout>
</ThemeProvider>
);
}
export default App;
所以我稍后会在导航/页脚中使用 ThemeSwitcher,并通过全局状态查看用户的选择
【问题讨论】:
标签: reactjs redux react-redux redux-toolkit