Connected-react-router: TypeError: Cannot read property 'pathname' of undefined

Created on 12 Nov 2018  路  28Comments  路  Source: supasate/connected-react-router

Looks like this is a regression of https://github.com/supasate/connected-react-router/issues/54, and potentially related to https://github.com/supasate/connected-react-router/issues/183

But I am getting a TypeError: Cannot read property 'pathname' of undefined error when simply following the docs.

// reducers.ts
import { combineReducers } from 'redux'
import { connectRouter } from 'connected-react-router'

export const createRootReducer = (history) => combineReducers({
  routing: connectRouter(history)
})
// store.ts
import { createBrowserHistory } from 'history'
import { createStore, applyMiddleware } from 'redux'
import { routerMiddleware } from 'connected-react-router'
import { createRootReducer } from './reducers'

export const history = createBrowserHistory()

export const store = createStore(
  createRootReducer(history),
  applyMiddleware(routerMiddleware(history))
)
// app.tsx
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { Route } from 'react-router-dom'
import { ConnectedRouter } from 'connected-react-router'
import { store, history } from './store'

const App = () => (
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <React.Fragment>
        <Route exact path="/" component={HomePage} />
        <Route path="/about" component={AboutPage} />
        <Route path="/topics" component={TopicsPage} />
      </React.Fragment>
    </ConnectedRouter>
  </Provider>
)

ReactDOM.render(<App />, document.getElementById('app'))
// versions
"react": "^16.6.0"
"react-dom": "^16.6.0"
"react-redux": "^5.1.0"
"react-router-dom": "^4.3.1"
"redux": "^4.0.1"
"connected-react-router": "^5.0.1"
"history": "^4.7.2"

Most helpful comment

Just a note that I also faced this error while using NavLink on react-router-dom 5.1.2. The error happened because I forgot the to attribute. It might be useful to make this error clearer.

All 28 comments

same here

Having the same problem.

102 | _this.unsubscribe = context.store.subscribe(function () {
103 | // Extract store's location
^ 104 | var _toJS = toJS(getIn(context.store.getState(), ['router', 'location'])),
105 | pathnameInStore = _toJS.pathname,
^ 106 | searchInStore = _toJS.search,
107 | hashInStore = _toJS.hash; // Extract history's location
108 |

I downgraded to v4.3 and that seemed to fix it. Not ideal though, as I try to keep everything up to date using https://www.npmjs.com/package/npm-check-updates

same issue

// reducers.ts
import { combineReducers } from 'redux'
import { connectRoute } from 'connected-react-router'

export const createRootReducer = (history) => combineReducers({
  routing: connectRouter(history)
})
// store.ts
import { createBrowserHistory } from 'history'
-- import { createStore, applyMiddleware } from 'redux'
++ import { createStore, applyMiddleware, compose } from 'redux'
import { routerMiddleware } from 'connected-react-router'
import { createRootReducer } from './reducers'

export const history = createBrowserHistory()

export const store = createStore(
  createRootReducer(history),
-- applyMiddleware(routerMiddleware(history))
++ // maybe there need a "compose" function
++ compose(applyMiddleware(routerMiddleware(history)))
)

@centuryPark are you suggesting that this is a fix?

@darewreck54 I do not have his code ,but in my project it works well .

// store.js
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { routerMiddleware, connectRouter } from 'connected-react-router';
import * as reducers from './reducers';

export default (history, initialState) => {
 // redux 璋冭瘯鎻掍欢閰嶇疆
 const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
 return createStore(
  combineReducers(
   {
     ...reducers,
       router: connectRouter(history),
    }
   ),
   initialState,
   composeEnhancer(
    applyMiddleware(
       routerMiddleware(history),
     thunkMiddleware
     )
   )
 );
};
/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Route, Switch } from 'react-router-dom';
import { Provider } from 'react-redux';
import createBrowserHistory from 'history/createBrowserHistory';
import { ConnectedRouter } from 'connected-react-router';
import App from './component/app';
import configureStore from './redux/store';
import './style/style.scss';

const initState = {};
const history = createBrowserHistory();
const store = configureStore(history, initState);
ReactDOM.render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <Switch>
        <Route path="/" component={App} />
      </Switch>
    </ConnectedRouter>
  </Provider>,
  document.getElementById('root')
);

js /package.json "connected-react-router": "^5.0.1", "history": "^4.7.2", "react": "^16.5.2", "react-dom": "^16.5.2", "react-redux": "^5.1.0", "react-router-dom": "^4.3.1", "redux": "^4.0.1", "redux-thunk": "^2.3.0"

Same issue. These needs to be fixed.

@greevz It might be related to the requirement that routerReducer must be placed under key router, while you seem to use routing.

Check https://github.com/supasate/connected-react-router/blame/master/README.md#L42

Same issue here. Trying to migrate from react-router-redux. Followed the docs and I get this error. Have tried several old version as well, but nothing is working.

I have verified that I am using the router key as well.

@mshick, could you please show how you set up the store, reducers and if you have any selectors that are using router state?

Downgrading to "connected-react-router": "^4.5.0", worked in the meantime. Version 5.0.0 started causing the TypeError: Cannot read property 'pathname' of undefined error.

for me the same error! tks, i make downgrade will work

Same error too:

"dependencies": {
    "@material-ui/core": "^3.5.1",
    "axios": "^0.18.0",
    "connected-react-router": "^5.0.1",
    "history": "^4.7.2",
    "react": "^16.6.3",
    "react-dom": "^16.6.3",
    "react-redux": "^5.1.1",
    "react-router-dom": "^4.3.1",
    "react-scripts": "2.1.1",
    "redux": "^4.0.1",
    "redux-devtools-extension": "^2.13.5",
    "redux-saga": "^0.16.2"
  }

Failed prop type: The prop location is marked as required in ConnectedRouter, but its value is undefined.
in ConnectedRouter (created by Connect(ConnectedRouter))
in Connect(ConnectedRouter) (at App.js:8)
in App (at src/index.js:14)
in Provider (at src/index.js:12)

Failed prop type: The prop action is marked as required in ConnectedRouter, but its value is undefined.
in ConnectedRouter (created by Connect(ConnectedRouter))
in Connect(ConnectedRouter) (at App.js:8)
in App (at src/index.js:14)
in Provider (at src/index.js:12)

Uncaught TypeError: Cannot read property 'pathname' of undefined
at ConnectedRouter.js:105
at Object.dispatch (redux.js:214)
at dispatch (:1:38288)
at middleware.js:72

store.js

import { createBrowserHistory } from 'history'
import { createStore, applyMiddleware, combineReducers, compose } from 'redux'
import { connectRouter, routerMiddleware } from 'connected-react-router'
import createSagaMiddleware from 'redux-saga';
import reducers from './containers/Auth/reducers'
import { composeWithDevTools } from 'redux-devtools-extension'

import { clickReducer } from './reducers/clickReducer';

// Create a history of your choosing (we're using a browser history in this case)
const history = createBrowserHistory()

const rootReducer = combineReducers({
  click: clickReducer,
  auth: reducers.auth,
  route: connectRouter(history),
})

const sagaMiddleware = createSagaMiddleware()

const store = createStore(
  rootReducer,
  composeWithDevTools(
    applyMiddleware(
      routerMiddleware(history),
      sagaMiddleware
    )
  )
)

function* rootSaga() {
  yield [ ]
}

sagaMiddleware.run(rootSaga)

export { store, history }

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { store, history } from './store';
import { ConnectedRouter } from 'connected-react-router'


ReactDOM.render((
  <Provider store={store}>

    <App history={history} />

  </Provider>
  ), document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();

app.js

import React from 'react'
import PropTypes from 'prop-types'
import { ConnectedRouter } from 'connected-react-router'
import routes from './routes'

const App = ({ history }) => {
  return (
    <ConnectedRouter history={history}>
      { routes }
    </ConnectedRouter>
  )
}

App.propTypes = {
  history: PropTypes.object,
}

export default App

routes.js

import React from 'react'
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";

import Login from '../containers/Auth/Login'
import NoMatch from '../containers/NoMatch'

const routes = (
  <Switch>
    <Route exact path="/" component={Login} />
    <Route component={NoMatch} />
  </Switch>
)

export default routes

@lucassimon You have router reducer under key route (in store.js). It should be router.

@lucassimon You have router reducer under key route (in store.js). It should be router.

Jesus. Thanks @sgal

I downgraded to v4.3 and that seemed to fix it. Not ideal though, as I try to keep everything up to date using https://www.npmjs.com/package/npm-check-updates

Are you talking about history or connected-react-router ?

geiIn.js has function parameter "state", and whereas other combined reducers ARE in this variable in form of the initial state OBJECTS (f.e. state.user or state.products), the router (state.router) is a Reducer FUNCTION and not object, so there is no property "pathname" on it. Please investigate the issue asap, as downgrading the version does not help..

Found a solution. Do not define a router props when combining reducers, but pass it in the createStore call as connectRouter(history)(rootReducer), f.e.

root-reducer.js

export default combineReducers({
    user: userReducer,
    products: productsReducer,
    // whatever reducers you have
});

store.js

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

instrumenter = window.__REDUX_DEVTOOLS_EXTENSION__();
export const history = createBrowserHistory();
export const rootReducer = createRootReducer;
const initialState: any = {};

export const store = createStore(
    connectRouter(history)(rootReducer),
    initialState,
    compose(
        applyMiddleware(routerMiddleware(history)),
        instrumenter,
    ),
);

Worked like charm for me.

Add router reducer into root reducer by passing history to connectRouter. Note: The key MUST be router.

// reducers.ts
import { combineReducers } from 'redux'
import { connectRouter } from 'connected-react-router'

export const createRootReducer = (history) => combineReducers({
--   routing: connectRouter(history)
++   router: connectRouter(history)
})

I have same problem ,because I use immutable. https://github.com/supasate/connected-react-router/issues/54

// app.tsx
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { Route,Router } from 'react-router-dom'
import { ConnectedRouter } from 'connected-react-router'
import { store, history } from './store'

const App = () => (
  <Provider store={store}>
    <ConnectedRouter history={history}>

-- <React.Fragment>
++ <Router>
        <Route exact path="/" component={HomePage} />
        <Route path="/about" component={AboutPage} />
        <Route path="/topics" component={TopicsPage} />
-- <React.Fragment>
++ </Router>
    </ConnectedRouter>
  </Provider>
)

ReactDOM.render(<App />, document.getElementById('app'))

The current setup documentation refers to version 5.0.0 and 5.0.1. It's very possible that you are installing a different version that is set up differently.

I tracked down the problem to line 105 in ConnectedRouter.js

var _toJS = toJS(getIn(context.store.getState(), ['router', 'location'])),
            pathnameInStore = _toJS.pathname,
            searchInStore = _toJS.search,
            hashInStore = _toJS.hash; // Extract history's location

I paused execution in the debugger to see what was going on. The problem is that getIn(context.store.getState(), ['router', 'location']) returns undefined. However if I remove 'location' from the array, it gets the router object no problem. And, sure enough, location is a valid key on the router object. At first I thought the getIn function was broken. It should be returning the nested location object on router, but it returns undefined instead.

But then I inspected context.store.getState() in the debugger and found that the "router" key had _another_ nested router object inside of it. So when getIn() tries to find the location key via the array ['router', 'location'], it fails, because the only key present on router is another nested router.
screen shot 2019-02-20 at 7 36 12 pm

The solution for me was to _NOT_ use combineReducers

This causes a nested "router" key:
combineReducers({ router: connectRouter(history) })

This works as intended:
connectRouter(history)

if you're having this problem, and you can track it down to the getIn function, then the issue is likely related to how your redux store is being constructed

In case anyone is having the same problem: Using <Router path='/'> worked fine for me, but I was having an issue when trying to access state.router.location in the state directly (location was undefined). The issue in my case was that I'm using immutable 4.0.0-rc.12 and this API is using immutable 3.8.2, so instead I had to rewrite my access in mapStateToProps to (router as any).toJS().location

Just a note that I also faced this error while using NavLink on react-router-dom 5.1.2. The error happened because I forgot the to attribute. It might be useful to make this error clearer.

Same issue here. Is anyone has better solution ? I'm also migrate from react-route-redux to connect-react-router.
I build the project from https://github.com/briancappello/flask-react-spa
and upgrade the dependencies .

i follow @miestr solution it is ok but I think maybe has better solution .
So welcome any better idea .

error stack

Uncaught TypeError: Cannot read property 'pathname' of undefined
    at createPath (history.js:70)
    at createHref (history.js:366)
    at eval (redux.js:361)
    at Array.forEach (<anonymous>)
    at assertReducerShape (redux.js:359)
    at combineReducers (redux.js:422)
    at createReducer (reducers.js?9c0a:11)
    at configureStore (configureStore.js?2ddb:35)
    at Module.eval (index.js?7df2:24)
    at eval (index.js:109)


reducer.js

import { combineReducers } from 'redux'
import { connectRouter } from 'connected-react-router'
import formReducer from 'redux-form/es/reducer'

import { loadingBarReducer } from 'react-redux-loading-bar'

import securityReducer from 'security/reducer'
import flashReducer from 'site/reducers/flash'


const createReducer = (injectedReducers) => combineReducers({
    router: connectRouter(injectedReducers),
    security: securityReducer,
    flash: flashReducer,
    form: formReducer,
    loadingBar: loadingBarReducer,

    ...injectedReducers,
})
export default createReducer

configureStore.js

import { applyMiddleware, compose, createStore } from 'redux'
import { routerMiddleware } from 'connected-react-router'
import { connectRouter } from 'connected-react-router'
import { loadingBarMiddleware } from 'react-redux-loading-bar'
import createSagaMiddleware from 'redux-saga'
import createReducer from 'reducers'
import getSagas from 'sagas'
import { flashClearMiddleware } from 'site/middleware/flash'

const isDev = process.env.NODE_ENV !== 'production'
const hasWindowObject = typeof window === 'object'

const sagaMiddleware = createSagaMiddleware()

export default function configureStore(initialState, history) {
  const middlewares = [
    sagaMiddleware,
    routerMiddleware(history),
    loadingBarMiddleware({ promiseTypeSuffixes: ['REQUEST', 'FULFILL'] }),
    flashClearMiddleware,
  ]

  const enhancers = [
    applyMiddleware(...middlewares),
  ]

  const composeEnhancers =
    isDev && hasWindowObject && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
      ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
      : compose
  const store = createStore(
    createReducer(history),
    initialState,
    composeEnhancers(...enhancers)
  )

  // extensions
  store.runSaga = sagaMiddleware.run
  store.injectedReducers = {}
  store.injectedSagas = {}

  let runningSagas = sagaMiddleware.run(function *() {
    yield getSagas()
  })

  if (module.hot) {
    module.hot.accept('./reducers', () => {
      const nextCreateReducer = require('./reducers').default
      store.replaceReducer(connectRouter(history)(nextCreateReducer(store.injectedReducers)))
    })

    module.hot.accept('./sagas', () => {
      const nextGetSagas = require('./sagas').default
      runningSagas.cancel()
      runningSagas.done.then(() => {
        runningSagas = sagaMiddleware.run(function *() {
          yield nextGetSagas()
        })
      })
    })
  }

  return store
}

here is my dependencies

"dependencies": {
    "@babel/polyfill": "7.4.3",
    "@hot-loader/react-dom": "^16.8.6",
    "acorn": "^6.4.1",
    "babel-polyfill": "^6.26.0",
    "chalk": "2.4.2",
    "classnames": "^2.2.6",
    "compression": "1.7.4",
    "connected-react-router": "^6.8.0",
    "core-js": "^3.6.4",
    "date-fns": "^2.11.0",
    "fontfaceobserver": "2.1.0",
    "history": "4.9.0",
    "hoist-non-react-statics": "3.3.0",
    "immer": "3.0.0",
    "immutable": "^3.8.2",
    "intl": "1.2.5",
    "invariant": "2.2.4",
    "ip": "1.1.5",
    "isomorphic-fetch": "^2.2.1",
    "js-cookie": "^2.2.1",
    "lodash": "^4.17.15",
    "minimist": "^1.2.5",
    "normalize.css": "^8.0.1",
    "path-to-regexp": "^6.1.0",
    "prop-types": "15.7.2",
    "query-string": "^6.11.1",
    "react": "16.8.6",
    "react-bulma-components": "^3.2.0",
    "react-dom": "16.8.6",
    "react-helmet": "6.0.0-beta",
    "react-highlight": "^0.12.0",
    "react-intl": "2.8.0",
    "react-loadable": "^5.5.0",
    "react-redux": "^7.2.0",
    "react-redux-loading-bar": "^4.6.0",
    "react-router-dom": "5.0.0",
    "react-svg": "^11.0.14",
    "redux": "4.0.1",
    "redux-form": "^8.2.3",
    "redux-saga": "1.0.2",
    "reselect": "4.0.0",
    "sanitize.css": "8.0.0",
    "seamless-immutable": "^7.1.4",
    "styled-components": "4.2.0",
    "utf-8-validate": "^5.0.2",
    "warning": "^4.0.3"
  },
  "devDependencies": {
    "@types/react": "^16.9.23",
    "add-asset-html-webpack-plugin": "3.1.3",
    "canvas": "^2.6.1",
    "circular-dependency-plugin": "5.0.2",
    "compare-versions": "3.4.0",
    "compression-webpack-plugin": "2.0.0",
    "coveralls": "3.0.3",
    "css-loader": "2.1.1",
    "eslint": "5.16.0",
    "eslint-config-airbnb": "17.1.0",
    "eslint-config-airbnb-base": "13.1.0",
    "eslint-config-prettier": "4.1.0",
    "eslint-import-resolver-webpack": "0.11.1",
    "eslint-plugin-import": "2.17.2",
    "eslint-plugin-jsx-a11y": "6.2.1",
    "eslint-plugin-prettier": "3.0.1",
    "eslint-plugin-react": "7.12.4",
    "eslint-plugin-react-hooks": "1.6.0",
    "eslint-plugin-redux-saga": "1.0.0",
    "express": "^4.17.1",
    "express-http-proxy": "^1.6.0",
    "fibers": "^4.0.2",
    "file-loader": "3.0.1",
    "html-loader": "0.5.5",
    "html-webpack-plugin": "3.2.0",
    "image-webpack-loader": "4.6.0",
    "imports-loader": "0.8.0",
    "jest-cli": "24.7.1",
    "jest-dom": "3.1.3",
    "jest-styled-components": "^6.3.4",
    "jsdom": "^16.2.1",
    "json-loader": "^0.5.7",
    "lint-staged": "8.1.5",
    "ngrok": "3.1.1",
    "node-plop": "0.18.0",
    "node-sass": "^4.13.1",
    "null-loader": "0.1.1",
    "offline-plugin": "5.0.6",
    "plop": "2.3.0",
    "pre-commit": "1.2.2",
    "prettier": "1.17.0",
    "react-app-polyfill": "0.2.2",
    "react-hot-loader": "^4.12.20",
    "react-test-renderer": "16.8.6",
    "react-testing-library": "6.1.2",
    "redbox-react": "^1.6.0",
    "resolve-url-loader": "^3.1.1",
    "rimraf": "2.6.3",
    "sass": "^1.26.3",
    "sass-loader": "^8.0.2",
    "shelljs": "0.8.3",
    "style-loader": "0.23.1",
    "stylelint": "10.0.1",
    "stylelint-config-recommended": "2.2.0",
    "stylelint-config-styled-components": "0.1.1",
    "stylelint-processor-styled-components": "1.6.0",
    "svg-url-loader": "2.3.2",
    "terser-webpack-plugin": "1.2.3",
    "url-loader": "1.1.2",
    "webpack": "^4.42.1",
    "webpack-bundle-analyzer": "^3.6.1",
    "webpack-cli": "3.3.0",
    "webpack-dev-middleware": "3.6.2",
    "webpack-hot-middleware": "2.24.3",
    "webpack-pwa-manifest": "^4.2.0",
    "whatwg-fetch": "3.0.0"
  }

index.js

import 'babel-polyfill'

// this must come before everything else otherwise style cascading doesn't work as expected
import 'main.scss'

import { AppContainer as HotReloadContainer } from 'react-hot-loader'
import { areComponentsEqual } from 'react-hot-loader';
import React from 'react'
import ReactDOM from 'react-dom'
import {createBrowserHistory} from 'history'

import configureStore from 'configureStore'
import App from 'components/App'
import { login } from 'security/actions'
import { flashInfo } from 'site/actions'
import SecurityApi from 'security/api'
import { storage } from 'utils'


const APP_MOUNT_POINT = document.getElementById('app')

const initialState = {}
const history = createBrowserHistory()
const store = configureStore(initialState, history)

const renderRootComponent = (Component) => {
  ReactDOM.render(
    <HotReloadContainer>
      <Component store={store} history={history} />
    </HotReloadContainer>,
    APP_MOUNT_POINT
  )
}

const token = storage.getToken()
store.dispatch(login.request())
SecurityApi.checkAuthToken(token)
  .then(({ user }) => {
    store.dispatch(login.success({ token, user }))
  })
  .catch(() => {
    store.dispatch(login.failure())
  })
  .then(() => {
    store.dispatch(login.fulfill())
    renderRootComponent(App)
    const isAuthenticated = store.getState().security.isAuthenticated
    const alreadyHasFlash = store.getState().flash.visible
    if (isAuthenticated && !alreadyHasFlash) {
      store.dispatch(flashInfo('Welcome back!'))
    }
  })

if (module.hot) {
  module.hot.accept('./components/App.js', () => {
    ReactDOM.unmountComponentAtNode(APP_MOUNT_POINT)
    const NextApp = App.default
      areComponentsEqual(NextApp)
    renderRootComponent(NextApp)
  })
}

App.js

import React from 'react'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'connected-react-router'
import Helmet from 'react-helmet'
import  { history } from './index'
import { NavBar, ProgressBar } from 'components'
import { SITE_NAME, COPYRIGHT } from 'config'
import Routes from 'routes'

const AppLayout = () => (
  <div className="fixed-nav-top">
    <Helmet titleTemplate={`%s - ${SITE_NAME}`}
            defaultTitle={SITE_NAME}
    />
    <ProgressBar />
    <header>
      <NavBar />
    </header>
    <main>
      <Routes />
    </main>
    <footer className="center">
       Copyright {new Date().getFullYear()} {COPYRIGHT}
    </footer>
  </div>
)
export default (props) => (
  <Provider store={props.store}>
    <ConnectedRouter history={history}>
      <AppLayout />
    </ConnectedRouter>
  </Provider>
)

For me, this arrived when I had not passed the value of prop "to" in NavLink. I hope this may work for a few people over here. 馃槃

Was this page helpful?
0 / 5 - 0 ratings

Related issues

austsinovich picture austsinovich  路  4Comments

bmueller-sykes picture bmueller-sykes  路  4Comments

pachuka picture pachuka  路  4Comments

slightlytyler picture slightlytyler  路  5Comments

BerndWessels picture BerndWessels  路  3Comments