从Redux迁移到Redux Toolkit

16

我刚接触React并尝试通过编码来学习。

我需要一些关于代码的帮助/建议,将这个Redux store转换为Redux Toolkit。我在这里使用一个名为configureStore的函数。改用来自 '@reduxjs/toolkit' 的 'configureStore' 的好方法是什么?

这是为了学习目的。那个'createRootReducer'来自我的reducers.js文件,它结合了所有reducer。

const createRootReducer = (history) => combineReducers({
    articles: articlesReducer,
    selection: selectionReducer,
});

我的 store.js 文件:

import { createBrowserHistory } from "history";
import { createStore, compose, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { routerMiddleware } from "connected-react-router";
import createRootReducer from "./reducers";

export const history = createBrowserHistory();

const storeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export default function configureStore(preloadedState) {
  const store = createStore(
    createRootReducer(history),
    preloadedState,
    storeEnhancers(applyMiddleware(routerMiddleware(history), thunk))
  );
  return store;
}

1个回答

16

注意:

目前有一个与 connected-react-router 相关的问题需要解决。

为了使您的设置正常工作,请确保安装 history v4.10.1 - 更高版本会导致错误:

Uncaught Could not find router reducer in state tree, it must be mounted under "router" #312


1. 中间件更新

redux-toolkit 已经包含了 redux-dev-toolsredux-thunk

如果您需要导入其他中间件,可以使用 getDefaultMiddleware 来添加它们。

如果您想要添加一些自定义中间件,但仍然希望添加默认中间件,那么 getDefaultMiddleware 是非常有用的:

因此,在这种情况下,您可以从 package.json 中删除 redux-thunk


2. 删除 redux 导入

您不再需要从 redux 导入 createStorecomposeapplyMiddlewarecombineReducers。所有这些都由 @reduxjs/toolkit 提供的 configureStore API 在内部处理。

您还可以从 package.json 中删除 redux


3. 从 @reduxjs/toolkitconfigureStore 应用参数。


更新后的 store 可以像这样:

// IMPORTANT: be sure to install history v4.10.1
// see open issue: https://github.com/supasate/connected-react-router/issues/312#issuecomment-647082777
import { createBrowserHistory, History } from "history";
import { configureStore } from "@reduxjs/toolkit";
import {
  routerMiddleware,
  connectRouter,
  RouterState
} from "connected-react-router";
import selectionReducer from "./reducers/selection";
import articlesReducer from "./reducers/articles";
import todosReducer, { I_TodoState } from "./reducers/todos";

export const history = createBrowserHistory();

// combineReducers will be handled internally by configureStore
const rootReducer = (history: History<any>) => ({
  articles: articlesReducer,
  selection: selectionReducer,
  todos: todosReducer,
  router: connectRouter(history)
});

const preloadedState = {};
export const store = configureStore({
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(routerMiddleware(history)),
  reducer: rootReducer(history),

  preloadedState
});
如果你在configureStorereducer参数中传递一个对象,那么reducers将被组合。所以你不再需要使用combineReducers创建一个rootReducer
这是一个演示链接: demo link 从你最初的帖子看,你只有三个中间件: __REDUX_DEVTOOLS_EXTENSION_COMPOSE__thunkrouterMiddleware
你看到的错误是因为@redux/toolkit为了正确保护你的状态不可变和序列化而提供额外的保护。它通过在默认的中间件中包含redux-immutable-state-invariant来实现这一点。
你之前的设置没有这个中间件,这就是为什么你现在只看到这些错误。如果你安装了redux-immutable-state-invariant,你会在之前的设置中看到这些错误。
要实现与之前相同的设置,你不需要包括defaultMiddleware,但检查你的reducers并了解为什么你的状态不可变和/或可序列化是一个非常好的主意。
下面是一个与你之前完全相同的设置,只是加入了@redux/toolkit
import { configureStore } from '@reduxjs/toolkit';
import { routerMiddleware, connectRouter } from 'connected-react-router';
import { createBrowserHistory } from 'history';
import thunk from 'redux-thunk';
import { rootReducer } from './reducer';

export const history = createBrowserHistory();

// combineReducers will be handled internally by configureStore
const rootReducer = (history) => ({
  articles: articlesReducer,
  selection: selectionReducer,
  router: connectRouter(history)
});

const preloadedState = {};
export const store = configureStore({
  middleware: [thunk, routerMiddleware(history)],
  reducer: rootReducer(history),
  preloadedState,
});

看起来开发工具已经配置好了:存储设置,所以我没有在这里添加它们。您仍应该能够在浏览器的开发工具中使用它们。

您应该查看为什么当前状态不是不可变的/可序列化的。这可能是由于状态中存在循环引用,或者状态在某个地方被直接修改。这可能会导致一些令人讨厌的错误,因为 Redux 只有在状态不可变时才真正发挥作用。

但是,您仍然可以在当前设置中使用 @redux/toolkit。


2
现有的reducer和action可以与redux toolkit一起使用。您发布的错误表明状态正在被突变。该错误是从immutableStateInvariantMiddleware抛出的。也许在您的状态中存在循环引用,导致中间件中出现无限递归。如果没有看到您的代码库,我很难判断。您可以尝试更改getDefaultMiddleware()getDefaultMiddleware({ immutableCheck: false }),并查看错误是否消失。如果确实消失了,则应检查并查看状态在何处发生了突变。Redux状态应始终是不可变的。 - Dan Kreiger
我用以下代码解决了这些错误:export const store = configureStore({ middleware: (getDefaultMiddleware) => getDefaultMiddleware({ immutableCheck: false, serializableCheck: false, }).concat(routerMiddleware(history)), reducer: rootReducer(history), preloadedState, });但这并不是正确的方法,有没有一种好的方法可以快速检查状态何时被改变,以便我真正摆脱这些问题? - user10727653
我在redux文件夹中没有node_modules/@reduxjs/toolkit/dist/redux-toolkit.esm.js这个文件,我只有dist、es、lib和src文件夹,其中没有toolkit文件夹。 - user10727653
嘿,对我来说通过StackOverflow进行这种调试有点困难。我在原始帖子中添加了一些代码,您可以使用它们。关键问题在于redux toolkit检测到了您之前设置未检测到的状态问题。请参见我上面发布的更新。希望这可以帮助您。 - Dan Kreiger
我已经发了一个新问题,与这个错误有关:https://stackoverflow.com/questions/69707164/argument-of-type-dispatch-any-promisevoid-is-not-assignable-to-paramet - user10727653
显示剩余14条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接