使用Vite从React16迁移至React18时遇路由中间件函数错误
我正在用Vite将React 16应用迁移至React 18,目前遇到路由与中间件相关问题,入口文件代码如下:
import React from 'react'; import { createRoot } from "react-dom/client"; import { Provider } from 'react-redux'; import { createBrowserHistory } from 'history'; import { createStore, applyMiddleware, compose } from 'redux'; import { BrowserRouter as Router, Route, cr } from "react-router-dom"; import createSagaMiddleware from 'redux-saga'; import globalStore from './reducers'; import sagas from './sagas'; import './i18n'; import './globalStyles.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; const history = createBrowserHistory(); const sagaMiddleware = createSagaMiddleware(); const enhancers = [applyMiddleware(routerMiddleware(history), sagaMiddleware)]; const composeEnhancers = process.env.NODE_ENV !== 'production' && typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ shouldHotReload: false, trace: true, traceLimit: 25, }) : compose; const store = createStore(globalStore(history), composeEnhancers(...enhancers)); sagaMiddleware.run(sagas); const rootElement = document.getElementById("root"); const root = createRoot(rootElement); root.render( <Provider store={store}> <Router history={history}> <App history={history} /> </Router> </Provider> ); serviceWorker.unregister();
运行时出现错误:
TypeError: middleware is not a function
问题原因及解决步骤
未导入且无需使用
routerMiddleware
代码中调用的routerMiddleware(history)既没有导入,而且React Router v6已经移除了对自定义history的直接支持,也不再需要这个中间件。这是导致"middleware is not a function"报错的核心原因——undefined被当成中间件传入applyMiddleware。修正React Router导入错误
代码里import { BrowserRouter as Router, Route, cr } from "react-router-dom";中的cr是拼写错误,直接删除即可。移除手动创建的history
React Router v6的BrowserRouter已经内置了history管理,不再接受historyprop,所以删掉createBrowserHistory()的创建代码,以及Router组件的history传入。组件内访问路由的方式调整
之前通过props传入history的方式可以换成React Router v6的useNavigate钩子,在App组件内直接调用即可。
修改后的完整代码
import React from 'react'; import { createRoot } from "react-dom/client"; import { Provider } from 'react-redux'; import { createStore, applyMiddleware, compose } from 'redux'; import { BrowserRouter as Router } from "react-router-dom"; import createSagaMiddleware from 'redux-saga'; import globalStore from './reducers'; import sagas from './sagas'; import './i18n'; import './globalStyles.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; const sagaMiddleware = createSagaMiddleware(); // 移除了routerMiddleware,只保留saga中间件 const enhancers = [applyMiddleware(sagaMiddleware)]; const composeEnhancers = process.env.NODE_ENV !== 'production' && typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ shouldHotReload: false, trace: true, traceLimit: 25, }) : compose; // 如果你的globalStore不再依赖history参数,这里去掉history传入 const store = createStore(globalStore(), composeEnhancers(...enhancers)); sagaMiddleware.run(sagas); const rootElement = document.getElementById("root"); const root = createRoot(rootElement); root.render( <Provider store={store}> <Router> <App /> </Router> </Provider> ); serviceWorker.unregister();
补充说明
如果你的reducer之前依赖history对象,需要调整reducer的逻辑。另外,React 18搭配Vite时,serviceWorker的配置可能需要改用Vite的PWA插件,不过暂时可以保留现有代码,后续再按需优化。
内容的提问来源于stack exchange,提问作者niko hustić

