React Router v4测试中MemoryRouter未设置match属性问题求助
match.params未定义的问题 我来帮你搞定这个测试报错的问题~你遇到的TypeError: Cannot read property 'params' of undefined,核心原因是**Topic组件作为路由匹配目标组件,必须被<Route>组件包裹,或者通过withRouter高阶组件处理,才能获取到match、location这些路由相关的props**。单纯把它放在<MemoryRouter>里是没用的——MemoryRouter只是提供了路由运行的上下文环境,但不会自动把路由属性注入给它的直接子组件。
下面给你两种符合React Router设计逻辑的解决方案:
方案1:在测试中用<Route>包裹Topic
把Topic放到<Route>组件中,并配置和实际项目一致的路径规则。当MemoryRouter的初始路由匹配上这个Route时,就会自动把match、params等props传递给Topic:
import React from 'react'; import { Topic } from './App'; import { MemoryRouter, Route } from 'react-router-dom' import TestRenderer from 'react-test-renderer'; test('it renders', () => { TestRenderer.create( <MemoryRouter initialEntries={['/topics/props-v-state']} initialIndex={0}> {/* 这里的path要和你项目中定义的Topic路由规则一致 */} <Route path="/topics/:topicId" component={Topic} /> </MemoryRouter> ); });
方案2:用withRouter高阶组件包装Topic
如果你的Topic组件不是直接被Route渲染的(比如是嵌套在其他组件内部使用),可以用react-router-dom提供的withRouter来包装它,让它能从路由上下文中获取所需的props:
首先修改你的App.js中Topic的导出逻辑:
import { withRouter } from 'react-router-dom'; // 假设你的原始组件定义是TopicComponent const TopicComponent = (props) => { // 你的组件逻辑,比如访问props.match.params.topicId return <div>{props.match.params.topicId}</div>; }; // 用withRouter包装后再导出 export const Topic = withRouter(TopicComponent);
之后你的测试代码就可以保持原来的写法,不需要额外的Route包裹也能正常获取match属性了:
import React from 'react'; import { Topic } from './App'; import { MemoryRouter } from 'react-router-dom' import TestRenderer from 'react-test-renderer'; test('it renders', () => { TestRenderer.create( <MemoryRouter initialEntries={['/topics/props-v-state']} initialIndex={0}> <Topic/> </MemoryRouter> ); });
补充说明
官方文档里的示例能直接用MemoryRouter渲染组件,通常是因为示例中的组件要么已经被Route包裹,要么已经通过withRouter处理过了。你之前手动传入match的方法虽然能临时解决问题,但不够贴近真实的路由运行场景,上面两种方案更符合React Router的设计思路哦。
内容的提问来源于stack exchange,提问作者Mike Bamford

