1
votes

I am trying to upgrade react-router from v3 to v4 and getting the following error when running the application :

Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in.

reducer :

import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';

import { login } from './login-reducer';

const reducers = combineReducers({
  routing: routerReducer,
  login
})

export default reducers;

store :

import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk';
import createHistory from 'history/createBrowserHistory'
import { routerMiddleware } from 'react-router-redux'

import reducers from '../reducers';

export const history = createHistory();
const routerMiddle = routerMiddleware(history);

const composeEnhancers =
  typeof window === 'object' &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
      // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
    }) : compose;

let middleware = [routerMiddle, thunk]
const enhancer = composeEnhancers(
  applyMiddleware(...middleware),
  // other store enhancers if any
);

const store = createStore(reducers, enhancer);

export default store;

index : import React from 'react';

import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import store, { history } from './store/createStore';
import { ConnectedRouter } from 'react-router-redux'

import { getRoutes } from './routes';

import './index.css';

ReactDOM.render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <div>{ getRoutes(store) }</div>
    </ConnectedRouter>
  </Provider>,
  document.getElementById('root')
);

routes :

import React from 'react';
import { Route } from 'react-router';

import App from './containers/App';
import Login from './containers/Login';
import Protected from './components/Protected';

export const getRoutes = (store) => {
  const authRequired = (nextState, replaceState) => {
    // Now you can access the store object here.
    const state = store.getState();

    if (!state.login.loggedIn || state.login.loggedIn == null) {
      // Not authenticated, redirect to login.
      replaceState({
        pathname: '/login',
        state: { nextPathname: nextState.location.pathname }
      });
    }
  };

  return (
    <div>
      <Route exact path="/" component={App} />
      <Route path="/login" component={Login} />
      <Route path="/protected" component={Protected} onEnter={authRequired} />
    </div>
  );
}

app :

import React, { Component } from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux'

import logo from '../logo.svg';
import './App.css';

class App extends Component {
  render() {
    const isLoggedIn = this.props.isLoggedIn;
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2><Link to="/">Welcome to React</Link></h2>
          <div className="app-nav">
            <nav>
              <Link to='about'>About</Link>
              <Link to='login'>{( isLoggedIn ? 'Logout' : 'Login' )}</Link>
              <Link to='protected'>Protected</Link>
            </nav>
          </div>
        </div>
        {this.props.children}
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    isLoggedIn:  (state.login.loggedIn ? state.login.loggedIn : false) 
  }
}

App = connect (
  mapStateToProps
)(App)

export default App;

Not sure what I'm missing to get this to work

**NOTE : I am still seeing this error even when I only have one route / and render a static component (single div with text)

3
did you fixed the issue ? - Vinz243

3 Answers

2
votes

A) You dont need react router redux at all with react router 4, specially if all you want is to render authenticated components.

B) The onEnter hook dont work this way in RR4, its the older way of doing route validation

{this.props.children} why are you still rendering child routes using props.children? All the child routes goes into the component it resides in.

If you are trying to learn rr4, i recommend checking this boilerplate for it https://github.com/touqeerkhan11/The-Ultimate-Boilerplate

1
votes

The problem is probably here

import { Link } from 'react-router';

react-router doesn't export Link, react-router-dom does.

import { Link } from 'react-router-dom';

You should probably import the Route component from react-router-dom as well.

1
votes

The issue had to do with the version of react-router-redux that was being used. When I added it to the project, I left off the @next