ReactJs / Redux Invariant Violation:在“Connect(LoginContainer)”的上下文或道具中找不到“store”
Posted
技术标签:
【中文标题】ReactJs / Redux Invariant Violation:在“Connect(LoginContainer)”的上下文或道具中找不到“store”【英文标题】:ReactJs/Redux Invariant Violation: Could not find "store" in either the context or props of "Connect(LoginContainer)" 【发布时间】:2017-11-11 12:28:13 【问题描述】:不知道为什么会出现此错误,它是在我将 connect
从 redux
添加到我的登录组件时发生的,因此我可以连接我的 store
。
失败 src/components/auth/Login.test.js
● 测试套件无法运行
不变违规:在“Connect(LoginContainer)”的上下文或道具中找不到“store”。要么将根组件包装在
<Provider>
中,要么将“store”作为道具显式传递给“Connect(LoginContainer)”。
Index.js
import React from 'react'
import ReactDOM from 'react-dom'
import Provider from "react-redux"
import createCommonStore from "./store";
import App from './App'
import css from './manage2.scss'
const store = createCommonStore();
const element = document.getElementById('manage2');
console.log("Index.js Default store", store.getState());
ReactDOM.render(
<Provider store=store> // <-- store added here
<App />
</Provider>, element);
store.js
import React from "react"
import applyMiddleware, combineReducers, compose, createStore from "redux"
import thunk from "redux-thunk"
import userReducer from "./reducers/UserReducer"
import authReducer from "./reducers/AuthReducer"
export const createCommonStore = (trackStore=false) =>
const reducers = combineReducers(
user: userReducer,
user: authReducer
);
//noinspection JSUnresolvedVariable
const store = createStore(reducers,
compose(
applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
if (trackStore)
store.subscribe((() =>
console.log(" store changed", store.getState());
));
return store;
;
App.js
import React from 'react'
import BrowserRouter as Router from 'react-router-dom'
import Routes from './components/Routes'
const supportsHistory = "pushState" in window.history
export default class App extends React.Component
render()
return (
<Router forceRefresh=!supportsHistory>
<Routes />
</Router>
);
Routes.js
import React from 'react'
import Route, Switch from 'react-router-dom'
import LoginContainer from './auth/Login'
import Dashboard from './Dashboard'
import NoMatch from './NoMatch'
const Routes = () =>
return (
<Switch>
<Route exact= true path="/" component= LoginContainer />
<Route path="/dashboard" component= Dashboard />
<Route component= NoMatch />
</Switch>
);
export default Routes
最后是 Login.js(为简洁起见删除了代码
import React from 'react'
import connect from "react-redux"
import bindActionCreators from 'redux';
import setCurrentUser from '../../actions/authActions'
import * as api from '../../services/api'
const mapDispatchToProps = (dispatch) =>
console.log('mapDispatchToProps', dispatch);
return
setUser: (user) =>
bindActionCreators(setCurrentUser(user), dispatch)
class LoginContainer extends React.Component
constructor(props)
super(props)
this.state = ;
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
handleChange(e)
handleSubmit(e)
render()
return (
<div className="app-bg">
...
</div>
)
export default connect(null, mapDispatchToProps)(LoginContainer);
登录测试
import React from 'react'
import ReactTestUtils from 'react-dom/test-utils'
import mount, shallow from 'enzyme'
import toJson from 'enzyme-to-json'
import missingLogin from '../../consts/errors'
import Login from './Login'
import Notification from '../common/Notification'
const loginComponent = shallow(<Login />);
const fakeEvent = preventDefault: () => '' ;
describe('<Login /> component', () =>
it('should render', () =>
const tree = toJson(loginComponent);
expect(tree).toMatchSnapshot();
);
it('should render the Notification component if state.error is true', () =>
loginComponent.setState( error: true );
expect(loginComponent.find(Notification).length).toBe(1);
);
);
describe('User Login', () =>
it('should fail if no credentials are provided', () =>
expect(loginComponent.find('.form-login').length).toBe(1);
loginComponent.find('.form-login').simulate('submit', fakeEvent);
expect(loginComponent.find(Notification).length).toBe(1);
const notificationComponent = shallow(<Notification message= missingLogin />);
expect(notificationComponent.text()).toEqual('Please fill out both username and password.');
);
it('input fields should be filled correctly', () =>
const credentials = username: 'leongaban', password: 'testpass' ;
expect(loginComponent.find('#input-auth-username').length).toBe(1);
const usernameInput = loginComponent.find('#input-auth-username');
usernameInput.value = credentials.username;
expect(usernameInput.value).toBe('leongaban');
const passwordInput = loginComponent.find('#input-auth-password');
passwordInput.value = credentials.password;
expect(passwordInput.value).toBe('testpass');
);
);
你觉得这里有什么问题?
【问题讨论】:
createCommonStore 代码在哪里, @ShubhamKhatri 刚刚添加了抱歉! store.js 在你的 index.js 中做一个 console.log() 看看你是否得到了商店的防御 能否提供login.test.js文件? 测试中如何连接store? 【参考方案1】:Redux 建议导出未连接的组件以进行单元测试。见他们的docs。
在 login.js 中:
// Named export for tests
export class LoginContainer extends React.Component
// Default export
export default connect(null, mapDispatchToProps)(LoginContainer);
在你的测试中:
// Import the named export, which has not gone through the connect function
import LoginContainer as Login from './Login';
然后,您可以直接在组件上指定来自商店的任何道具。
【讨论】:
谢谢,这就是我用来将登录组件导入到我的测试中的,但是我目前没有在我的登录代码中使用商店,如上所示。这可能是问题所在吗? @LeonGaban 这不是您在问题代码中所做的。您正在将连接的组件作为默认导出导入。这是将未连接的组件作为命名导出导入。 好的,这样做了,仍然出现错误。我在测试中还需要什么? gist.github.com/leongaban/770713a4d7f542c725c46cf5db47cae2 啊!就是这样!抱歉,我在路线测试中看到错误。所以提供者在测试内部工作!现在得到一个无法读取未定义的属性“应用”,但这是一个新错误。 18 小时前我可以检查你的答案。【参考方案2】:您需要在测试中将 store 作为 prop 或 context 传递。 mount 方法接受上下文作为另一个参数。
你如何在这里获得商店?您创建商店的方式与您在 app.js 中创建的方式相同
【讨论】:
您能否发布一个如何在开玩笑测试中执行此操作的示例?目前我正在使用 index.js 中的 Provider 组件将商店插入到我的应用程序中。真的不确定如何在我的测试中做到这一点。我的 index.js 位于我的问题的首位。【参考方案3】:你可以使用 React 的 contextType 或传递 propType。您需要将其声明为 prop 或 contextType。
Provider.contextTypes =
Store: React.PropTypes.object.isRequired
;
Provider.propTypes=
Store: React.PropTypes.object.isRequired
;
【讨论】:
这将进入哪个模块?还是在测试中?以上是关于ReactJs / Redux Invariant Violation:在“Connect(LoginContainer)”的上下文或道具中找不到“store”的主要内容,如果未能解决你的问题,请参考以下文章
reactjs - jest 快照测试嵌套的 redux “连接”组件
ReactJS + Redux + Reduc-thunk 无法调度承诺
如何正确地从 ReactJS + Redux 应用程序进行 REST 调用?
使用 ReactJS + Redux 时需要 componentWillReceiveProps 和 replaceProps 吗?