【问题标题】:Store does not have a valid reducer. Make sure the argument passed to combineReducers is an object商店没有有效的减速器。确保传递给 combineReducers 的参数是一个对象
【发布时间】:2021-11-06 15:44:28
【问题描述】:

ReactJSRedux-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


    【解决方案1】:

    你的错误信息告诉你去哪里看:

    Store 没有有效的 reducer。 确保参数通过 combineReducers 是一个对象,其值为 reducers。

    这里的问题是调用 combineReducers 时为您的 data 状态提供一个空对象。

    export const rootReducer = combineReducers({
        data: combineReducers({
            // Here is the problem. It needs a reducer.
        }),
        ui: combineReducers({
            theme: themeUiReducer
        }),
    });
    

    由于您现在根本没有使用 data 属性,因此最简单的方法是将其从您的状态中删除。

    export const rootReducer = combineReducers({
        ui: combineReducers({
            theme: themeUiReducer
        }),
    });
    

    如果你想为未来的 reducer 提供一个占位符,你可以提供一个“no-op” reducer 函数,它什么都不做。

    export const rootReducer = combineReducers({
        data: (state = null, action) => state,
        ui: combineReducers({
            theme: themeUiReducer
        }),
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-26
      • 2019-09-17
      • 1970-01-01
      • 1970-01-01
      • 2019-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多