5

I am trying to redirect to the page after signing out. However, every time when I sign out, it directs the page successfully. However, I still got the error

Cannot read property 'type' of undefined

Further research by "Pause on Caught Exceptions", it is related with react-router-redux.

enter image description here

So the line store.dispatch(push('/signin')) in the code below causes the issue. If I change to .map(() => ({ type: 'NOT_EXIST' }));, there will be no issue.

What may cause this? Thanks

actions/auth.action.js

export const signOutSucceedEpic = (action$, store) =>
  action$
    .ofType(SIGN_OUT_SUCCEED)
    .map(() => store.dispatch(push('/signin')));  // <- this line causes the issue

actions/index.js

import { combineEpics } from 'redux-observable';

export default combineEpics(
  // ...
  signOutSucceedEpic
);

index.js

import { Provider } from 'react-redux';
import { Route } from 'react-router-dom';
import { ConnectedRouter, routerMiddleware, push } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
import rootEpic from './actions/index';

const history = createHistory();
const routeMiddleware = routerMiddleware(history);
const epicMiddleware = createEpicMiddleware(rootEpic);

export const store = createStore(
  rootReducer,
  persistedState,
  composeWithDevTools(
    applyMiddleware(
      epicMiddleware,
      routeMiddleware
    )
  )
);

ReactDOM.render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <div>
        <Route path="/signin" component={SignIn} />
        <Route exact path="/" component={Home} />
      </div>
    </ConnectedRouter>
  </Provider>,
  document.getElementById('root')
);
Hongbo Miao
  • 31,551
  • 46
  • 124
  • 206
  • i think you forgot to specify the type, write it like this: `store.dispatch({type: 'abc', data: push('/signin')});` check the [**DOC**](http://redux.js.org/docs/api/Store.html#example) example. – Mayank Shukla Jul 30 '17 at 04:40

1 Answers1

1

The issue is you're calling store.dispatch inside a map operator, mapping to the return value of that store.dispatch() but it doesn't return anything, so the value undefined is getting emitted by your epic and then dispatched by redux-observable on your behalf. Then react-router-redux receives that undefined value but it assumes only actions with a type property will be dispatched, so it causes the error in question.

I recommend re-examining the redux-observable docs as calling store.dispatch directly inside your epics is an anti-pattern, and not necessary. Your epic should emit a stream of actions that will be dispatched for you by redux-observable, so in this case you could just remove the store.dispatch and instead map to the result of the push() action:

export const signOutSucceedEpic = (action$, store) =>
  action$
    .ofType(SIGN_OUT_SUCCEED)
    .map(() => push('/signin'));
jayphelps
  • 14,317
  • 2
  • 38
  • 52
  • Thank you so much!! Just put correct code here `.map(() => push('/signin'));` – Hongbo Miao Jul 30 '17 at 05:07
  • You're writing some nonsense. `push('/signin')` indeed returns `undefined`. Look here http://engineering.blogfoster.com/higher-order-components-theory-and-practice/ and explain with your theory why `dispatch(push('/signin'));` works fine in that example and throws in OP's issue. – Green Oct 18 '17 at 07:14
  • @Green this answer fixed his particular issue. Calling `push` from `react-router-redux` does not return `undefined`, it returns an action that you dispatch. Calling dispatch directly with it will indeed cause the transition, but you will receive the same error the OP did if you do it inside `map` because your epic should always emit actions, not `undefined`. Using `store.dispatch` directly inside epics is an anti-pattern and will be removed in v1.0.0 of redux-observable to prevent confusion. Instead, epics should emit actions that the middleware will dispatch for you. – jayphelps Oct 18 '17 at 19:59
  • I had a similar issue. Turns out I was calling a method connected to the dispatcher that didn't return an action (it was dispatching other actions but none itself). Un-connecting that method solved my problem. – doque Nov 15 '17 at 15:02