supasate / connected-react-router

A Redux binding for React Router v4
MIT License
4.73k stars 594 forks source link

Uncaught TypeError: Cannot read property 'location' of undefined upgrading from react-router-redux #328

Open colin-byrne-1 opened 5 years ago

colin-byrne-1 commented 5 years ago

I am updating from react-router-redux, and keep getting Uncaught TypeError: Cannot read property 'location' of undefined. I am not sure if this is a bug (I see similar errors caused by package version compatabilities, but mine look OK), or if my implementation of proptypes needs to change, or another issue is at play.

//package.json

    "prop-types": "15.7.2",
    "react": "16.8.6",
    "react-dom": "16.8.6",
    "react-redux": "6.0.0",
    "redux": "4.0.1",
    "redux-thunk": "2.2.0",

//app.js

import React from 'react';
import { connect } from 'react-redux';
import { push } from 'connected-react-router'
import classNames from 'classnames';
import PropTypes from 'prop-types';

class App extends React.Component {
    static propTypes = {
        isAuthenticated: PropTypes.bool.isRequired,
        isAdmin: PropTypes.bool.isRequired,
        children: PropTypes.shape().isRequired,
        dispatch: PropTypes.func.isRequired,
        location: PropTypes.shape({
            pathname: PropTypes.string
        })
    };

    static defaultProps = {
        location: undefined
    };

    logout = () => {
        this.props.dispatch(authLogoutAndRedirect());
    };

    goToIndex = () => {
        this.props.dispatch(push('/'));
    };

    goToLogin = () => {
        this.props.dispatch(push('/login'));
    };

    render() {
        const homeClass = classNames({
            active: this.props.location && this.props.location.pathname === '/'
        });
        const protectedClass = classNames({
            active: this.props.location && this.props.location.pathname === '/policy_controls'
        });
        const loginClass = classNames({
            active: this.props.location && this.props.location.pathname === '/login'
        });

        return (
            <div className="app">
                <nav className="navbar navbar-default">
                    ...
                </nav>
                <div>
                    {this.props.children}
                </div>
            </div>
        );
    }
}

const mapStateToProps = (state, ownProps) => {
    return {
        isAuthenticated: state.auth.isAuthenticated,
        isAdmin: state.auth.isAdmin,
        location: state.router.location.pathname,    
        pathname: state.router.location.pathname,
        search: state.router.location.search,
        hash: state.router.location.hash,
    };
};

export default connect(mapStateToProps)(App);
export { App as AppNotConnected };

//reducers/index.js

import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router'
import authReducer from './auth';
import dataReducer from './data';

export default (history) => combineReducers({
    router: connectRouter(history),
    auth: authReducer,
    data: dataReducer,
});`

//index.js

import React from 'react';
import ReactDOM from 'react-dom';
import createHistory from 'history/createBrowserHistory';

import { authLoginUserSuccess } from './actions/auth';
import Root from './containers/Root/Root';
import configureStore from './store/configureStore';

const initialState = {};
const target = document.getElementById('root');

const history = createHistory();
const store = configureStore(initialState, history);

const node = (
    <Root store={store} history={history} />
);

const token = sessionStorage.getItem('token');
let user = {};
try {
    user = JSON.parse(sessionStorage.getItem('user'));
} catch (e) {
    // Failed to parse
}

if (token !== null) {
    store.dispatch(authLoginUserSuccess(token, user));
}

ReactDOM.render(node, target);

//store/configurestore.js


/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */

import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger';

import { createBrowserHistory } from 'history'
import { createStore, applyMiddleware, compose } from 'redux';
import { routerMiddleware } from 'connected-react-router';
import createRootReducer from '../reducers'

import rootReducer from '../reducers';
import DevTools from '../containers/Root/DevTools';

export const history = createBrowserHistory()

export default function configureStore(initialState, history) {
    const logger = createLogger();

    // Build the middleware for intercepting and dispatching navigation actions
    const reduxRouterMiddleware = routerMiddleware(history);

    const middleware = applyMiddleware(thunk, logger, reduxRouterMiddleware);

    const middlewareWithDevTools = compose(
        middleware,
        DevTools.instrument()
    );

    // Add the reducer to your store on the `router` key
    // Also apply our middleware for navigating
    const store = createStore(createRootReducer(history), initialState, middlewareWithDevTools);

    if (module.hot) {
        module.hot
            .accept('../reducers', () => {
                const nextRootReducer = require('../reducers/index'); // eslint-disable-line global-require

                store.replaceReducer(nextRootReducer);
            });
    }

    return store;
}
SavageWilliam commented 4 years ago

+1 @cobyrne09 - did you find a solution to this?

colin-byrne-1 commented 4 years ago

@SavageWilliam I ended up rolling back a couple packages, and haven't had any trouble. I would try rolling back react-router-redux before redux or redux-thunk. I am guessing the only one that matters is react-router-redux. I haven't had any issues with the alpha version. That said, I am sure something is going to force me to update sooner or later and I'll be sure to check back in on this thread when it does.

here are my current versions:

"prop-types": "15.7.2",
"react": "16.8.4",
"react-dom": "16.8.4",
 "react-router-redux": "5.0.0-alpha.9",
 "redux": "3.7.2",
 "redux-thunk": "2.2.0",
mohantorrez commented 4 years ago

+1

Am also facing this issue

Mickaz89 commented 4 years ago

Any solution for this issue ?

caleyshemc commented 4 years ago

I don't have a proper solution for this, but I do have a hack that worked for me.

let history = { location: null };

if (typeof window === 'object') {
  history = createBrowserHistory();
}
szkkteam commented 4 years ago

I had the same issue today when I tried to migrate from react-router-redux to connected-react router. For me the solution was that you need to provide the history param also in the hot reload part of your code.

if (module.hot) {
        module.hot
            .accept('../reducers', () => {
                const nextRootReducer = require('../reducers/index');
                store.replaceReducer(nextRootReducer(history));
            });
    }

There is also an example here: link