3

I am trying to setup my react app.

I am trying to understand how to integrate the routes with the app.

When I try to use AppRouter in my ReactDOM, I get an error message that says I shouldn't use Route outside the Router.

I don't understand what the error means. I can get rid of the error message when I remove the AppRouter line from my Provider, but that only creates a new error with the provider. I can't find an example of how to get started.

My app.js has:

import React from 'react';
import ReactDOM from 'react-dom';

import { Provider } from 'react-redux';
import AppRouter from './routers/AppRouter.js';
import { BrowserRouter } from 'react-router-dom';
import configureStore from './store/configureStore.js';
// import { startSetUsers } from './actions/users';


import 'normalize.css/normalize.css';
import './styles/styles.scss';
import './firebase/firebase';
// import * as firebaseui from 'firebaseui'

//import './playground/promises';


const store = configureStore();

const jsx = (
    <Provider store={store}>
        <AppRouter />
    </Provider>
);

ReactDOM.render(jsx, document.getElementById('app'));

My AppRouter has:

import React from 'react';
import { connect } from 'react-redux';
import { BrowserRouter, Route, Switch, Link, NavLink, withRouter } from 'react-router-dom';
import Header from '../components/Header.js';
import Footer from '../components/Footer.js';

import Dashboard from '../components/home/Dashboard.js';
import Landing from '../components/home/Landing.js';
import ErrorNotice from '../components/ErrorNotice.js';
import SignIn from '../components/auth/RegisterPage.js';
import Pending from '../components/auth/PendingPage.js';
import SignInSuccess from '../components/auth/SignInSuccess.js';


import Users from '../components/users/UserDashboard.js';

// this Higher Order Component wraps the app and listens for Firebase auth change state event
// when this state changes, it updates the store
import withAuthentication from '../hoc/withAuthentication';
import AuthenticatedRoute from  '../components/auth/AuthenticatedRoute';

const AppRouter = () => {
    return (
            <div>
                <Header />
                <Switch>
                    <Route path="/" exact={true} component={Landing} />
                    {/* Authentication Related routes */}
                    <Route path="/Signin" component={SignIn} />
                    {/* This route no longer required. Was used when uiConfig has a redirect URL */}
                    {/* <Route path="/Loading" component={SignInSuccess} /> */}
                    <Route path="/Pending" component={Pending} />
                    {/* PUBLIC ROUTES */}
                    <Route path="/Users" component={Users} />
                    <Route path="/Menu" component={Menu} />
                    {/* AUTHENTICATED ROUTES */}
                    {/* Places routes that require authenitcation here and use the AuthenticatedRoute */}
                    <AuthenticatedRoute path="/Dashboard" component={Dashboard} />
                    <Route component={ErrorNotice} />
                </Switch>
                <Footer />
            </div>
    )
}



// set up passing of store state as component props
const mapStateToProps = state => ({
    authUser: state.sessionState.authUser,
});

// connect this component to the store
// wrap withRouter to ensure that Links work: => https://reacttraining.com/react-router/core/guides/redux-integration/blocked-updates
export default withRouter(connect(mapStateToProps)(AppRouter));

Can anyone see where I'm going wrong?

revised AppRouter.js

import React from "react";
import { connect } from "react-redux";
import {
  BrowserRouter,
  Route,
  Switch,
  Link,
  NavLink,
  withRouter
} from "react-router-dom";
import Header from "../components/Header.js";
import Footer from "../components/Footer.js";

import Dashboard from "../components/home/Dashboard.js";
import Landing from "../components/home/Landing.js";
import ErrorNotice from "../components/ErrorNotice.js";
import SignIn from "../components/auth/RegisterPage.js";
import Pending from "../components/auth/PendingPage.js";
import SignInSuccess from "../components/auth/SignInSuccess.js";

import About from "../components/footerlinks/company/About.js";
import Users from "../components/users/UserDashboard.js";

// this Higher Order Component wraps the app and listens for Firebase auth change state event
// when this state changes, it updates the store
import withAuthentication from "../hoc/withAuthentication";
import AuthenticatedRoute from "../components/auth/AuthenticatedRoute";

const AppRouter = () => {
  <BrowserRouter>
    <div>
      <Header />
      <Switch>
        <Route path="/" exact={true} component={Landing} />
        {/* Authentication Related routes */}
        <Route path="/Signin" component={SignIn} />
        {/* This route no longer required. Was used when uiConfig has a redirect URL */}
        {/* <Route path="/Loading" component={SignInSuccess} /> */}
        <Route path="/Pending" component={Pending} />
        {/* PUBLIC ROUTES */}
        <Route path="/About" component={About} />
        <Route path="/Users" component={Users} />
        <Route path="/Menu" component={Menu} />
        {/* AUTHENTICATED ROUTES */}
        {/* Places routes that require authenitcation here and use the AuthenticatedRoute */}
        <AuthenticatedRoute path="/Dashboard" component={Dashboard} />
        <Route component={ErrorNotice} />
      </Switch>
      <Footer />
    </div>
  </BrowserRouter>;
};

// set up passing of store state as component props
const mapStateToProps = state => ({
  authUser: state.sessionState.authUser
});

// connect this component to the store
// wrap withRouter to ensure that Links work: => https://reacttraining.com/react-router/core/guides/redux-integration/blocked-updates
export default connect(mapStateToProps)(AppRouter);

console errors after removing withRouter from the import statement:

Warning: Failed prop type: Invalid prop `component` of type `object` supplied to `Route`, expected `function`.
    in Route (created by AppRouter)
    in AppRouter (created by Connect(AppRouter))
    in Connect(AppRouter)
    in Provider

Warning: AppRouter(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
printWarning @ warning.js:33
warning @ warning.js:57
warnIfInvalidElement @ ReactCompositeComponent.js:51
mountComponent @ ReactCompositeComponent.js:193
mountComponent @ ReactReconciler.js:45
performInitialMount @ ReactCompositeComponent.js:370
mountComponent @ ReactCompositeComponent.js:257
mountComponent @ ReactReconciler.js:45
performInitialMount @ ReactCompositeComponent.js:370
mountComponent @ ReactCompositeComponent.js:257
mountComponent @ ReactReconciler.js:45
performInitialMount @ ReactCompositeComponent.js:370
mountComponent @ ReactCompositeComponent.js:257
mountComponent @ ReactReconciler.js:45
mountComponentIntoNode @ ReactMount.js:104
perform @ Transaction.js:143
batchedMountComponentIntoNode @ ReactMount.js:126
perform @ Transaction.js:143
batchedUpdates @ ReactDefaultBatchingStrategy.js:62
batchedUpdates @ ReactUpdates.js:97
_renderNewRootComponent @ ReactMount.js:319
_renderSubtreeIntoContainer @ ReactMount.js:401
render @ ReactMount.js:422
(anonymous) @ app.js:29
__webpack_require__ @ bootstrap 8dde10c53183363cc06e:19
(anonymous) @ bundle.js:50261
__webpack_require__ @ bootstrap 8dde10c53183363cc06e:19
module.exports @ bootstrap 8dde10c53183363cc06e:62
(anonymous) @ bootstrap 8dde10c53183363cc06e:62
invariant.js:42 Uncaught Error: AppRouter(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object
10
  • Use theBrowserRouter you have imported from react-router-dom as the topmost component in AppRouter to wrap everything inside it and it should work. const AppRouter = () => <BrowserRouter>{/* ... */}</BrowserRouter> Commented Jul 16, 2018 at 0:45
  • Hi @Tholle - I tried it, but I get the same error. Commented Jul 16, 2018 at 0:52
  • Do that and also remove the withRouter HOC you are using on the export and try again. Commented Jul 16, 2018 at 0:53
  • Do you mean like this: export default(connect(mapStateToProps)(AppRouter)); ? I know its wrong - there is a long list of errors generated by trying this, but I'm lost for where to start in figuring out what is required. Commented Jul 21, 2018 at 1:23
  • Can you create an example on codesandbox.io/s/new with BrowserRouter added? Commented Jul 21, 2018 at 1:44

4 Answers 4

2
+50

I think the problem is that your AppRouter is not returning anything. In the arrow function if you write () => {statement} it will execute the statement but if you write () => statement it will return it. So you should modify the AppRouter to:

const AppRouter = () => (
  <BrowserRouter>
    ...
  </BrowserRouter>
);

More info about the arrow functions:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Hope it helps.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi @peetya, thanks very much for this. I tried your suggestion, but I get an error that says: Failed prop type: Invalid prop component of type object supplied to Route, expected function. Although the landing page does load. This could be a step towards a solution. I'll read more into it.
You're welcome, let me know if you need further help, I'll do my best :)
1

Hi @Mel I faced similar issue a few days back, and i resolved it as following:

  1. In your index.html, check that your id is app and not root.

  2. Modify your app.js to have:

    const jsx = (
     <Provider store={store}>
        <BrowserRouter>
          <AppRouter />
        </BrowserRouter>
     </Provider>
    );
    
  3. Now, your AppRouter needs to be a class based component, so it would become as following after modifying:

// All your imports come here

  class AppRouter extends Component {
     render() {
       let routes = (
          <Switch>
            <Route path="/" exact={true} component={Landing} />
            <Route path="/Signin" component={SignIn} />
            <Route path="/Pending" component={Pending} />
            <Route path="/Users" component={Users} />
            <Route path="/Menu" component={Menu} />
            <AuthenticatedRoute path="/Dashboard" component={Dashboard} />
            <Route component={ErrorNotice} />
          </Switch>
       );
       return (
         <div>
            <Header />
            {routes}
            <Footer />
        </div>
       );
     }
   }
   const mapStateToProps = state => ({
      authUser: state.sessionState.authUser
   });
   export default withRouter(connect(mapStateToProps)(AppRouter));

If you still face issues, let me know, I can share more code.

Hope it helps! Happy Coding! ;)

3 Comments

thanks so much for this. I tried it, but I still get 2 errors, as follows:1. failed prop type: Invalid prop component of type object supplied to Route, expected function 2.A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
Hi @Mel, with reference to you current errors: 1. This error has something to do with returning multiple statements in some of your component, please see this for reference. 2. Second error means that some component of yours passed in <Route component={whateverComponent} /> is not correct. Please check this link, I have created a JSFiddle example for syntax of functional and class based components.
I have updated the Fiddle example to be more informative: Here's the updated link: jsfiddle.net/kapil5harma/0e4zopf3/23
0

index.js or appRouter.js should contain this type of routes written

import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import store from './redux-state.js';


ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <App>
        <Switch>
          <Route path="/" exact={true} component={Landing} />
          <Route exact path="/" component={Home}/>
          <Route component={Error404} />
        </Switch>
      </App>
    </BrowserRouter>
  </Provider>,
  document.getElementById('appRoot'),
  renderCommon
);

while in your app.js you can write following and it should work fine

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

function mapStateToProps(state) {
  return {};
}

function mapDispatchToProps(dispatch) {
  return {};
}

class App extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      {this.props.children}
    )
  }
}

Comments

-1

Just copy and paste the code. It will work. Message me if you have any issue

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Header from '../components/Header.js';
import Footer from '../components/Footer.js';
import NotFound from "../../ui/pages/notfound";

import Dashboard from '../components/home/Dashboard.js';
import Landing from '../components/home/Landing.js';
import ErrorNotice from '../components/ErrorNotice.js';
import SignIn from '../components/auth/RegisterPage.js';
import Pending from '../components/auth/PendingPage.js';
import SignInSuccess from '../components/auth/SignInSuccess.js';


import Users from '../components/users/UserDashboard.js';

// this represent ur actions
import { togglemenu } from "../../../actions/index";
import { bindActionCreators } from 'redux';


class AppRouter extends Component {
  render() {
    return (
      <BrowserRouter>
        <Header />
          <div>
            <Switch>
              <Route path="/" exact={true} component={Landing} />
              <Route path="/Signin" exact={true} component={SignIn} />
              <Route path="/Pending" exact={true} component={Pending} />
              {/* PUBLIC ROUTES */}
              <Route path="/Users" exact={true} component={Users} />
              <Route path="/Menu" exact={true} component={Menu} />
              <Route component={NotFound} />
            </Switch>
          </div>
        <Footer />
     </BrowserRouter>
   )
 }
}


function mapStateToProps(state) {
  return {
   // ur redux state
   home: state.home
  }
}
function mapDispatchToProps(dispatch) {
  return bindActionCreators({
  // ur redux action
  togglemenu: togglemenu
  }, dispatch)
}

 export default connect(mapStateToProps, mapDispatchToProps)(AppRouter);

4 Comments

Thanks for sharing your code @Abundance - I don't seem to be adopting a similar approach to that you've used in preparing your code - so I'm not sure how to use your ideas.
Explain to me how you setup your project so i can help you.
Telling just copy and paste is not a constructive answer.
it's as set out above. Thanks for trying to help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.