React-redux: Using 'store' on base class

Created on 18 May 2016  路  4Comments  路  Source: reduxjs/react-redux

I'm using a base class for some components. However when using redux I get an issue with connect. This only happens when trying to use connect with the base class 'DockerWindow'. If I only use it on a child 'DockChat' it works. How can I access the 'store' on 'DockerWindow' (a base class)?

-> DockChat
-> DockOnline

Error:

connect.js?243b:129Uncaught TypeError: Cannot read property 'store' of undefined

Packages: React 15.0.2, React-Redux 4.4.5, Redux 3.5.2

// index.js
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import configureStore from './store/configureStore'
import Docker from './containers/Docker.js'
import './styles/docker.scss';

var dockerElement = document.querySelector('Docker');
var sessionKey = dockerElement.dataset.sessionKey || '';
var version = dockerElement.dataset.version || '0.0.1';
const store = configureStore({},version);

render(
    <Provider store={store}>
        <Docker session={sessionKey} />
    </Provider>,
    dockerElement
);


// configureStore.js
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
import * as storage from 'redux-storage'
import createEngine from 'redux-storage-engine-localstorage';

import rootReducer from '../reducers';
import {mapDispatchToProps} from '../actions';

export default function configureStore(initialState,version) {
    const reducer = storage.reducer(combineReducers(rootReducer));
    const engine = createEngine('mytest');
    const middleware = storage.createMiddleware(engine);
    let store = createStore(reducer,initialState, compose(applyMiddleware(middleware)));
    const load = storage.createLoader(engine);
    return store;
}


// actions
export const APP_UPDATE_VERSION = 'APP_UPDATE_VERSION';
export function appUpdateVersion(version) {
    return {
        type: APP_UPDATE_VERSION,
        version: version
    }
}

export function mapDispatchToProps(dispatch) {
    return {
        appUpdateVersion: (version) => { dispatch(appUpdateVersion(version)); }
    };
}


// reducers.
import {
    APP_UPDATE_VERSION    } from '../actions'
const initialStateApp = {
    version:"0.0.1"
};
export function app(state = initialStateApp, action) {
    switch (action.type) {
        case APP_UPDATE_VERSION:
            // Somehow clear engine/all states
            return state;        
        default:
            return state;
    }
}
const rootReducer = {
    app
};
export default rootReducer;

export function mapStateToProps(state) {
    return {
        app: state.app
    }
}



// DockerWindow.js
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { mapDispatchToProps } from '../actions'
import {聽mapStateToProps }聽from '../reducers'

class DockerWindow extends React.Component {
    constructor(props) {
        super(props);
    }
    render(body) {
        return <div>{body}</div>
    }
}
export default connect(mapStateToProps,mapDispatchToProps)(DockerWindow);


// DockOnline.js
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { mapDispatchToProps } from '../actions'
import {聽mapStateToProps }聽from '../reducers'

import DockerWindow from './DockerWindow';

class DockOnline extends DockerWindow {
    constructor(props) {
        super(props);
    }
    render(){
        return super.render(<div>child</div>)
    }
}
export default connect(mapStateToProps,mapDispatchToProps)(DockOnline);

Most helpful comment

Please don鈥檛 use inheritance with React. It is actively discouraged.
Rather than do

class DockOnline extends DockerWindow {
    render(){
        return super.render(<div>child</div>)
    }
}

you should do something like

class DockOnline extends React.Component {
    render(){
        return (
            <DockerWindow>
                <div>child</div>
            </DockerWindow>
        );
    }
}

and then use this.props.children inside DockerWindow.

All 4 comments

Finally after hours of trying it works.

For 'base class' use contextTypes only

DockerWindow.contextTypes = {
    store: PropTypes.object
};
export default (DockerWindow);

and in children use connect

DockOnline.contextTypes = {
    store: PropTypes.object
};
export default connect(mapStateToProps,mapDispatchToProps)(DockOnline);

Please don鈥檛 use inheritance with React. It is actively discouraged.
Rather than do

class DockOnline extends DockerWindow {
    render(){
        return super.render(<div>child</div>)
    }
}

you should do something like

class DockOnline extends React.Component {
    render(){
        return (
            <DockerWindow>
                <div>child</div>
            </DockerWindow>
        );
    }
}

and then use this.props.children inside DockerWindow.

Thanks for that gaeron, as a dev I've had some issues understanding how to extend classes. Now finally it all makes sense 馃憤

@gaearon Why is it discouraged to use inheritance? especially if many components are gonna be reusing same functionality and props from the base class?

Was this page helpful?
0 / 5 - 0 ratings