反应警告:失败的上下文类型:所需的上下文“路由器”未在“组件”中指定
Posted
技术标签:
【中文标题】反应警告:失败的上下文类型:所需的上下文“路由器”未在“组件”中指定【英文标题】:React Warning: Failed Context Types: Required context `router` was not specified in `Component` 【发布时间】:2015-07-26 01:07:48 【问题描述】:我正在尝试测试一个需要 react-router 与 app.js 分开的 React 组件。
我有一个使用 mixin Router.Navigation 进行重定向的组件,如下所示:
var React = require('react'),
Router = require('react-router');
var Searchbar = React.createClass(
mixins : [Router.Navigation],
searchTerm: function(e)
if (e.keyCode !== 13)
return;
this.context.router.transitionTo('/someRoute/search?term=' + e.currentTarget.value)
,
render: function()
return (
<div className="searchbar-container">
<input type="search" placeholder="Search..." onKeyDown=this.searchTerm />
</div>
)
);
module.exports = Searchbar;
我试图为此编写一个测试,但碰壁了。除了我无法测试 transitionTo 是否按预期工作之外,我还在 Jest 测试中遇到了以下错误消息:
警告:上下文类型失败:router
未在 Searchbar
中指定所需的上下文。
有谁知道我如何摆脱警告和奖励问题,如何测试转换是否按预期工作?
我已经对此和 Github 上的对话进行了研究:https://github.com/rackt/react-router/issues/400 是我发现的最接近该问题的。看起来我需要单独导出路由器,但是在没有警告的情况下运行组件测试似乎有很多开销https://github.com/rackt/react-router/blob/master/docs/guides/testing.md
真的是这样吗?
【问题讨论】:
您找到解决方案了吗? 没有,我已经成功了,但我仍在努力。这不是特别紧急,因为它们只是警告消息,但它们很烦人。不过我会整理一下。 嗨@Tom 我终于找到了解决方案,因为 BinaryMuse 的最后一段让我走上了正轨。我用代码发布了自己的答案。 谢谢你让我知道伙计! 【参考方案1】:在 React Router 的 0.13 版本中,mixin Navigation
和 State
已被弃用。相反,它们提供的方法存在于对象this.context.router
上。这些方法不再被弃用,但如果您明确使用this.context.router
,则不需要mixin(但您需要直接声明contextTypes
);或者,您可以使用 mixin,但不需要直接使用 this.context.router
。 mixin 方法将为您访问它。
在任何一种情况下,除非你通过 React Router 渲染你的组件(通过Router#run
),router
对象不会提供给上下文,当然你不能调用转换方法。这就是警告告诉你的——你的组件期望路由器被传递给它,但它找不到它。
要单独测试(不创建路由器对象或通过Router#run
运行组件),您可以将模拟的router
对象放在组件上下文的正确位置,并测试您调用transitionTo
使用正确的值。
【讨论】:
这个答案也被弃用了:github.com/rackt/react-router/blob/master/UPGRADE_GUIDE.md 像社区中的许多其他人一样,我们误解了“mixins 正在消失”的情绪。 Mixins 和 React.createClass 不会很快消失,而且绝对不会消失,直到 ES6 类有更好的答案来取代 mixins 所做的事情(比如装饰器)。 这个答案的最后一段给了我解决方案。有关详细信息,请参阅我自己的答案。 新的升级指南在这里github.com/rackt/react-router/blob/latest/upgrade-guides/…【参考方案2】:因为 router
严重依赖于 React 鲜为人知的 context
功能,所以您需要像 here 中描述的那样对它进行存根
var stubRouterContext = (Component, props, stubs) =>
return React.createClass(
childContextTypes:
makePath: func,
makeHref: func,
transitionTo: func,
replaceWith: func,
goBack: func,
getCurrentPath: func,
getCurrentRoutes: func,
getCurrentPathname: func,
getCurrentParams: func,
getCurrentQuery: func,
isActive: func,
,
getChildContext ()
return Object.assign(
makePath () ,
makeHref () ,
transitionTo () ,
replaceWith () ,
goBack () ,
getCurrentPath () ,
getCurrentRoutes () ,
getCurrentPathname () ,
getCurrentParams () ,
getCurrentQuery () ,
isActive () ,
, stubs);
,
render ()
return <Component ...props />
);
;
并像这样使用:
var stubRouterContext = require('./stubRouterContext');
var IndividualComponent = require('./IndividualComponent');
var Subject = stubRouterContext(IndividualComponent, someProp: 'foo');
React.render(<Subject/>, testElement);
【讨论】:
【参考方案3】:这是我的 Jest 文件,可以完整回答这个问题。 BinaryMuse 的最后一段让我走上了正轨,但我发现代码示例总是最有帮助的,所以在这里供将来参考。
jest.dontMock('./searchbar');
describe('Searchbar', function()
var React = require('react/addons'),
Searchbar = require('../../components/header/searchbar'),
TestUtils = React.addons.TestUtils;
describe('render', function()
var searchbar;
beforeEach(function()
Searchbar.contextTypes =
router: function()
return
transitionTo: jest.genMockFunction()
;
;
searchbar = TestUtils.renderIntoDocument(
<Searchbar />
);
);
it('should render the searchbar input', function()
var searchbarContainer = TestUtils.findRenderedDOMComponentWithClass(searchbar, 'searchbar-container');
expect(searchbarContainer).toBeDefined();
expect(searchbarContainer.props.children.type).toEqual('input');
);
);
);
希望这对将来的其他人有所帮助。
【讨论】:
【参考方案4】:我的回答不是专门针对 Jest 的,但它可能会帮助遇到同样问题的人。
我创建了一个类来包装router
context
。
然后在您的测试中添加<ContextWrapper><YourComponent/></ContextWrapper>
包装其他内容(例如ReactIntl
)会很有用。
请注意,您将失去使用浅渲染的可能性,但ReactIntl
已经是这种情况。
希望对某人有所帮助。
ContextWrapper.js
import React from 'react';
export default React.createClass(
childContextTypes:
router: React.PropTypes.object
,
getChildContext ()
return
router:
;
,
render ()
return this.props.children;
);
【讨论】:
以上是关于反应警告:失败的上下文类型:所需的上下文“路由器”未在“组件”中指定的主要内容,如果未能解决你的问题,请参考以下文章
警告:子上下文类型失败:提供给“CellRenderer”的“数字”类型的子上下文“virtualizedCell.cellKey”无效,应为“字符串”