connected-react-router
connected-react-router copied to clipboard
TypeError: Cannot read property 'pathname' of undefined
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"
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') );
/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 inConnectedRouter
, but its value isundefined
. 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 inConnectedRouter
, but its value isundefined
. 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
(instore.js
). It should berouter
.
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
.
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. 😄
That issue is driving me insane! 😝 I've tried all the proposed solutions here, including a complete check for any <Navlink />
and <Link />
components which would be missing the "to" prop.
I laso followed React Router docs on migrating to v6 to make sure no other hook or function could be messing things up, but unfortunately I'm afraid I'll have to downgrade React to v16 and all other packages accordingly. ...
{
"dependencies": {
"connected-react-router": "^6.9.2",
"react-router-dom": "6.2.1",
"react-redux": "^7.2.6",
"react": "^17.0.2",
"redux": "^4.1.2"
}
}
...
But how to implement on react 18