React-Router-v4测试报错:不可在<Router>外使用<Route>或withRouter()
解决React Router v4的"Invariant Violation: You should not use or withRouter() outside a "错误
嘿,这个错误我太熟了!咱们一步步来把它搞定~
为啥会出这个错?
说白了就是:你代码里的某个组件用了<Route>、withRouter或者其他React Router的路由工具,但这个组件没有被<Router>(比如BrowserRouter、HashRouter这类顶层路由容器)包裹起来。React Router需要一个顶层的Router来管理整个应用的路由上下文,没有它的话,路由相关的组件根本不知道该怎么工作。
先把你的index.js改对
看你已经导入了BrowserRouter,大概率是包裹的顺序或者范围不对。尤其是你还用到了Redux的话,要注意Provider和Router的嵌套顺序——Router要放在Provider里面,这样路由组件才能正常访问Redux的store。
给你一个正确的index.js示例:
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import { BrowserRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; // 如果你用了Redux,必须导入这个 import store from './store'; // 导入你的Redux store实例 import registerServiceWorker from './registerServiceWorker'; ReactDOM.render( // 最外层是Redux的Provider,把store传进去 <Provider store={store}> {/* 然后用BrowserRouter包裹你的整个App */} <BrowserRouter> <App /> </BrowserRouter> </Provider>, document.getElementById('root') ); registerServiceWorker();
重点要保证:所有用到路由的组件(包括App里面的<Route>)都被<BrowserRouter>完全包裹住,不能有漏网之鱼。
测试文件也得同步修改
你说运行基础测试时出错,这十有八九是测试代码里直接渲染了App或者某个带路由的组件,但没给它套上Router。毕竟测试环境是独立的,不会自动继承你index.js里的Router上下文。
给你两种常见测试工具的修复方案:
用React Testing Library的情况
import React from 'react'; import { render } from '@testing-library/react'; import { BrowserRouter } from 'react-router-dom'; import App from './App'; test('App渲染正常', () => { // 渲染的时候一定要用BrowserRouter把App包起来 render( <BrowserRouter> <App /> </BrowserRouter> ); // 接下来写你的测试逻辑就行 });
用Enzyme的情况
import React from 'react'; import { mount } from 'enzyme'; import { BrowserRouter } from 'react-router-dom'; import App from './App'; test('带路由的App能正常挂载', () => { const wrapper = mount( <BrowserRouter> <App /> </BrowserRouter> ); // 你的测试断言逻辑 });
这里不推荐用shallow渲染带路由的组件,很容易因为上下文缺失出问题,用mount配合Router包裹是最稳妥的。
最后提个小提醒
要是你在某个组件里用了withRouter高阶组件来获取路由信息,这个组件同样必须被Router包裹才能正常工作,哪怕它是个深层嵌套的组件也一样。
内容的提问来源于stack exchange,提问作者incarnate
相关产品推荐
相关产品推荐

