Reputation: 261
I have the following question: I have a react class (dashboardContainer) which is visible only if user is logged in. This class (dashboardContainer) is extended by other class (Authorized), Authorized class checks if user logged in and get the user data if the data is not in the state. Both classes uses react-redux connect but when I executed it throws the next error:
Uncaught TypeError: Cannot read property 'store' of undefined at DashboardContainer.Connect (connectAdvanced.js:122) at new DashboardContainer (DashboardContainer.jsx:57) at eval (ReactCompositeComponent.js:294) at measureLifeCyclePerf (ReactCompositeComponent.js:75) at ReactCompositeComponentWrapper._constructComponentWithoutOwner (ReactCompositeComponent.js:293) at ReactCompositeComponentWrapper._constructComponent (ReactCompositeComponent.js:279) at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:187) at Object.mountComponent (ReactReconciler.js:45) at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:370) at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:257)
this is the code
import React,{Component} from 'react'
import PropTypes from 'prop-types'
import lodash from 'lodash'
import auth from '../../../utils/localStorage'
import {browserHistory} from 'react-router'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import * as userActions from '../../../actions/userActions'
import * as appActions from '../../../actions/appActions'
class AuthorizedComponent extends Component {
constructor(props){
super(props)
}
async componentDidMount(){
const { routes } = this.props; // array of routes
const { router } = this.props;
console.log(this.props.userActions)
//check if user is logged (token in localstorage)
if (!auth.loggedIn() ) browserHistory.push('/login')
if(this.props.user == null ){
//get user
const response = await this.props.userActions.getUserByToken()
//get all roles available for this route
const user = await response
console.log('authorized')
console.log(user)
console.log('----------')
}
}
}
function mapStateToProps(state){
return{
user: state.user
}
}
function mapDispatchToProps(dispatch){
return {
userActions: bindActionCreators(userActions, dispatch),
appActions: bindActionCreators(appActions, dispatch)
}
}
export default connect( mapStateToProps , mapDispatchToProps )(AuthorizedComponent)
//export default AuthorizedComponent
this is the DashboardContainer class:
import React from 'react'
import PropTypes from 'prop-types'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import Dashboard from './Dashboard'
import HeaderContainer from '../Header/HeaderContainer'
import Authorized from '../Authorized/Authorized'
import * as userActions from '../../../actions/userActions'
import * as appActions from '../../../actions/appActions'
class DashboardContainer extends Authorized {
constructor(props) {
super(props)
}
render() {
return (<div className="">
<HeaderContainer />
<Dashboard
itemActive={'dashboard'}/>
</div>)
}
}
function mapStateToProps(state) {
return {
app: state.app,
sidebar: state.sidebar
}
}
function mapDispatchToProps(dispatch) {
return {
userActions: bindActionCreators(userActions, dispatch),
appActions: bindActionCreators(appActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(DashboardContainer)
I'm recently new at Redux and react and I have no idea if I am doing correctly or if there is another way to do this well.
Upvotes: 3
Views: 3141
Reputation: 86
Since you are connecting also the subclass to the store, there is no need to extend the connected component, rather extend the simple class like this:
// ...rest of code
export class AuthorizedComponent extends Component {
// ... rest of code
And import it like so when defining your Dashboard class:
import {Authorized} from '../Authorized/Authorized'
Now the DashboardContainer
constructor won't try to execute any magic of the connected AuthorizedComponent
, but only your defined code.
Upvotes: 3
Reputation: 555
Your connected DashboardContainer
's props are not getting set properly. And react-redux
uses props
or context
to get the store
and pass it to child components. See this line from react-redux
library
this.store = props[storeKey] || context[storeKey]
//storeKey is 'store' and as props are undefined you are getting the error
Your props are not getting set properly because your extending another connected(react-redux)
component. I don't know the exact reason behind this, but will try to find it and update my answer.
If you are not using DashboardContainer
's constructor for anything other than calling super
. Then you can remove it. Or make your DashboardContainer
extend React.Component
Edit:
React suggests that you shouldn't use inheritance
for components, rather use composition
. https://reactjs.org/docs/composition-vs-inheritance.html
So instead you can try something like this.
class AuthorizedComponent extends Component {
constructor(props) {
super(props);
this.state = {};
}
...
...
async componentDidMount(){
...
...
if(this.props.user == null ){
//get user
const response = await this.props.userActions.getUserByToken()
//get all roles available for this route
const user = await response
this.setState({authorized: true});
console.log('authorized')
console.log(user)
console.log('----------')
}
}
render() {
this.state.authorized
? <DashboardContainer />
: <span>Show some another component</span>
}
}
Upvotes: 0
Reputation: 73908
Make sure you are using a Provider
in order to pass state to child component.
It is possible that the container you defined does not have a reference to it, this could be a possible reasons why you are receiving error:
Cannot read property 'store' of undefined at DashboardContainer.Connect
Pseudo example:
<Provider store={store}>
<App/>
</Provider>, document.getElementById('app'))
Related interesting article.
Upvotes: 1