bcg
bcg

Reputation: 261

Extended class in React with Redux

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

Answers (3)

bambam
bambam

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

vs1682
vs1682

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

GibboK
GibboK

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

Related Questions