Difference between declaring JSX code in variable and in React component - reactjs

I've recently started playing around with Redux and quickly came across this error message : Warning: You cannot change <Router routes>; it will be ignored (I'm also using react-router). After a little search, I understood I had to declare my routes in a variable so they wouldn't get re-rendered.
So here's my code :
Routing.js
import React from 'react';
import { Router, browserHistory, Route, IndexRoute, Redirect } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import RouterUtils from 'src/utils/js/RouterUtils';
import MainContent from 'src/common/main-content/js/MainContent';
// modules loaded lazily
import IndexPage from 'src/views/index/js/IndexPage';
import Page403 from 'src/views/403/js/403';
import Page404 from 'src/views/404/js/404';
import LoginPage from 'src/views/login/js/LoginPage';
import GetBusiness from 'src/route-fetch-components/business-get/js/GetBusiness';
import BusinessesPage from 'src/views/businesses-list/js/BusinessesPage';
import BusinessPage from 'src/views/business-details/js/BusinessPage';
import GetJobSeeker from 'src/route-fetch-components/jobseeker-get/js/GetJobSeeker';
import JobSeekersPage from 'src/views/jobseekers-list/js/JobSeekersPage';
import JobSeekerPage from 'src/views/jobseeker-details/js/JobSeekerPage';
import GetJobOffer from 'src/route-fetch-components/job-offer-get/js/GetJobOffer';
import JobOffersPage from 'src/views/job-offers-list/js/JobOffersPage';
import JobOfferPage from 'src/views/job-offer-details/js/JobOfferPage.js';
import JobOfferCreatePage from 'src/views/job-offer-create/js/JobOfferCreatePage';
const lazyLoadComponent = lazyModule =>
(location, cb) => {
lazyModule(module => {
cb(null, module.default);
});
};
const redirectTo404 = () => {
RouterUtils.redirect('/404');
};
const routes = (
<div>
<Route path="/" component={MainContent}>
<IndexRoute getComponent={lazyLoadComponent(IndexPage)} />
<Route path="businesses">
<IndexRoute getComponent={lazyLoadComponent(BusinessesPage)} />
<Route path=":user_id" getComponent={lazyLoadComponent(GetBusiness)}>
<IndexRoute getComponent={lazyLoadComponent(BusinessPage)} />
<Route path="job-offers">
<IndexRoute onEnter={() => redirectTo404()} /> // TODO: Add a component to list all job offers related to a business
<Route path=":job_offer_id" getComponent={lazyLoadComponent(GetJobOffer)}>
<IndexRoute getComponent={lazyLoadComponent(JobOfferPage)} />
</Route>
</Route>
</Route>
</Route>
<Route path="jobseekers">
<IndexRoute getComponent={lazyLoadComponent(JobSeekersPage)} />
<Route path=":user_id" getComponent={lazyLoadComponent(GetJobSeeker)}>
<IndexRoute getComponent={lazyLoadComponent(JobSeekerPage)} />
/*<Route path="applications">
<IndexRoute onEnter={() => redirectTo404()} /> // TODO: Add a component to list all applications related to a jobseeker
<Route path=":application_id" getComponent={lazyLoadComponent(JobOfferPage)} />
</Route>*/
</Route>
</Route>
<Route path="job-offers">
<IndexRoute getComponent={lazyLoadComponent(JobOffersPage)} />
<Route path="create" getComponent={lazyLoadComponent(JobOfferCreatePage)} />
</Route>
<Route path="403" getComponent={lazyLoadComponent(Page403)} />
<Route path="404" getComponent={lazyLoadComponent(Page404)} />
</Route>
<Route path="login" getComponent={lazyLoadComponent(LoginPage)} />
<Redirect from="*" to="404" />
</div>);
export default class Routing extends React.Component {
constructor(props, context) {
super(props);
this.history = syncHistoryWithStore(browserHistory, context.store);
}
render() {
return (
<Router history={this.history}>
{routes}
</Router>
);
}
}
Routing.contextTypes = {
store: React.PropTypes.object.isRequired,
};
It works perfectly fine, but I would now like to make a component ouf of my routes. So I just take the JSX code out in a new component :
Routing.js
import React from 'react';
import { Router, browserHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import Routes from './Routes';
const routes = <Routes />;
export default class Routing extends React.Component {
constructor(props, context) {
super(props);
this.history = syncHistoryWithStore(browserHistory, context.store);
}
render() {
return (
<Router history={this.history}>
{routes}
</Router>
);
}
}
Routing.contextTypes = {
store: React.PropTypes.object.isRequired,
};
Routes.js
import React from 'react';
import { Route, IndexRoute, Redirect } from 'react-router';
import RouterUtils from 'src/utils/js/RouterUtils';
import MainContent from 'src/common/main-content/js/MainContent';
// components loaded lazily
import IndexPage from 'src/views/index/js/IndexPage';
import Page403 from 'src/views/403/js/403';
import Page404 from 'src/views/404/js/404';
import LoginPage from 'src/views/login/js/LoginPage';
import GetBusiness from 'src/route-fetch-components/business-get/js/GetBusiness';
import BusinessesPage from 'src/views/businesses-list/js/BusinessesPage';
import BusinessPage from 'src/views/business-details/js/BusinessPage';
import GetJobSeeker from 'src/route-fetch-components/jobseeker-get/js/GetJobSeeker';
import JobSeekersPage from 'src/views/jobseekers-list/js/JobSeekersPage';
import JobSeekerPage from 'src/views/jobseeker-details/js/JobSeekerPage';
import GetJobOffer from 'src/route-fetch-components/job-offer-get/js/GetJobOffer';
import JobOffersPage from 'src/views/job-offers-list/js/JobOffersPage';
import JobOfferPage from 'src/views/job-offer-details/js/JobOfferPage.js';
import JobOfferCreatePage from 'src/views/job-offer-create/js/JobOfferCreatePage';
const lazyLoadComponent = lazyModule =>
(location, cb) => {
lazyModule(module => {
cb(null, module.default);
});
};
const redirectTo404 = () => {
RouterUtils.redirect('/404');
};
const Routes = () => (
<div>
<Route path="/" component={MainContent}>
<IndexRoute getComponent={lazyLoadComponent(IndexPage)} />
<Route path="businesses">
<IndexRoute getComponent={lazyLoadComponent(BusinessesPage)} />
<Route path=":user_id" getComponent={lazyLoadComponent(GetBusiness)}>
<IndexRoute getComponent={lazyLoadComponent(BusinessPage)} />
<Route path="job-offers">
<IndexRoute onEnter={() => redirectTo404()} /> // TODO: Add a component to list all job offers related to a business
<Route path=":job_offer_id" getComponent={lazyLoadComponent(GetJobOffer)}>
<IndexRoute getComponent={lazyLoadComponent(JobOfferPage)} />
</Route>
</Route>
</Route>
</Route>
<Route path="jobseekers">
<IndexRoute getComponent={lazyLoadComponent(JobSeekersPage)} />
<Route path=":user_id" getComponent={lazyLoadComponent(GetJobSeeker)}>
<IndexRoute getComponent={lazyLoadComponent(JobSeekerPage)} />
/*<Route path="applications">
<IndexRoute onEnter={() => redirectTo404()} /> // TODO: Add a component to list all applications related to a jobseeker
<Route path=":application_id" getComponent={lazyLoadComponent(JobOfferPage)} />
</Route>*/
</Route>
</Route>
<Route path="job-offers">
<IndexRoute getComponent={lazyLoadComponent(JobOffersPage)} />
<Route path="create" getComponent={lazyLoadComponent(JobOfferCreatePage)} />
</Route>
<Route path="403" getComponent={lazyLoadComponent(Page403)} />
<Route path="404" getComponent={lazyLoadComponent(Page404)} />
</Route>
<Route path="login" getComponent={lazyLoadComponent(LoginPage)} />
<Redirect from="*" to="404" />
</div>
);
export default Routes;
Ahhhhh... Cleaner. Except it doesn't work anymore. My page doesn't load, and I get this error :
Warning: [react-router] Location "/" did not match any routes
Now I'm wondering : what's the difference between assigning my JSX code to a var, as const routes = (<div>...</div>) and declaring it in a React Component (actually a pure function here, but I tested both)?
Thanks in advance for your time!

Related

React won't render my newly created component accessed via route

Basically, I'm working on the DataTurks project but I've stumbled upon some problems linked to the frontend app named bazaar. I'm trying to create a new component and add a new route for it so I can access it. This is my code for my routes:
import React from 'react';
import {IndexRoute, Route} from 'react-router';
// import { isLoaded as isAuthLoaded, load as loadAuth } from 'redux/modules/auth';
import {
App,
Home,
NotFound,
TaggerLogin,
TaggerSpace,
TaggerCreate,
TaggerImport,
TaggerStats,
TaggerExport,
TaggerProjects,
TaggerAdd,
TaggerOveriew,
TaggerVisualize,
TaggerEdit,
TaggerOrg,
TaggerOrgProject,
TaggerError,
TaggerKeyBind,
TaggerContributors,
ConfirmMail
} from 'containers';
export default (store) => {
const requireLogin = (nextState, replace, cb) => {
const { auth: { user }} = store.getState();
if (!user) {
// oops, not logged in, so can't be here!
replace('/projects/login');
}
cb();
};
/**
* Please keep routes in alphabetical order
*/
return (
<Route path="/" component={App}>
<Route path="confirm" component={ConfirmMail}/> //THIS IS THE COMPONENT I'M TRYING TO ACCESS
{ /* Home (main) route */ }
<IndexRoute component={Home}/>
{ /* Routes requiring login */ }
<Route onEnter={requireLogin}>
<Route path="projects/create" component={TaggerCreate}/>
<Route path="projects/edit" component={TaggerEdit}/>
<Route path="projects/:orgName/create" component={TaggerCreate}/>
<Route path="projects/:orgName/import" component={TaggerImport}/>
<Route path="projects/:orgName/:projectName/edit" component={TaggerEdit}/>
<Route path="projects/:orgName/:projectName/keybind" component={TaggerKeyBind}/>
</Route>
{ /* Dataturks tool */}
<Route path="projects/login" component={TaggerLogin}/>
<Route path="projects/import" component={TaggerImport}/>
<Route path="projects/space" component={TaggerSpace}/>
<Route path="projects/stats" component={TaggerStats}/>
<Route path="projects/export" component={TaggerExport}/>
<Route path="projects" component={TaggerProjects}/>
<Route path="projects/add" component={TaggerAdd}/>
<Route path="projects/overview" component={TaggerOveriew}/>
<Route path="projects/visualize" component={TaggerVisualize}/>
<Route path="projects/errors" component={TaggerError}/>
<Route path="projects/:orgName" component={TaggerOrg} />
<Route path="projects/:orgName/:projectName" component={TaggerOrgProject} />
<Route path="projects/:orgName/:projectName/space" component={TaggerSpace}/>
<Route path="projects/:orgName/:projectName/export" component={TaggerExport}/>
<Route path="projects/:orgName/:projectName/overview" component={TaggerOveriew}/>
<Route path="projects/:orgName/:projectName/visualize" component={TaggerVisualize}/>
<Route path="projects/:orgName/:projectName/contributors" component={TaggerContributors}/>
{ /* Catch all route */ }
<Route path="*" component={NotFound} status={404} />
</Route>
);
};
What I'm trying to access is ConfirmMail component and route. The ConfirmMail component:
import React from 'react';
export default function ConfirmMail() {
const styles = require('./ConfirmMail.scss');
return (
<div className="container">
<div className={styles.loading + ' text-center'}>
<span className="glyphicon glyphicon-repeat glyphicon-refresh-animate gi-3x">
CONFIRMED
</span>
</div>
</div>
);
}
Also, the client.js:
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import createStore from './redux/create';
import ApiClient from './helpers/ApiClient';
import {Provider} from 'react-redux';
import { Router, browserHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import { ReduxAsyncConnect } from 'redux-async-connect';
import useScroll from 'scroll-behavior/lib/useStandardScroll';
import {persistStore} from 'redux-persist';
import getRoutes from './routes';
import { Segment } from 'semantic-ui-react';
const client = new ApiClient();
const _browserHistory = useScroll(() => browserHistory)();
console.log('window data is', window._data);
const store = createStore(_browserHistory, client, window.__data);
const history = syncHistoryWithStore(_browserHistory, store);
class AppProvider extends React.Component {
constructor() {
super();
this.state = { rehydrated: false };
}
componentWillMount() {
persistStore(store, { blacklist: ['routing', 'dataturksReducer'] }, () => {
this.setState({ rehydrated: true });
});
}
render() {
const component = (
<Router render={(props) =>
<ReduxAsyncConnect {...props} helpers={{client}} filter={item => !item.deferred} />
} history={history}>
{getRoutes(store)}
</Router>
);
if (!this.state.rehydrated) {
return (<div><Segment basic loading/></div>);
} else if (this.state.rehydrated) {
console.log('rehydrating ', component);
return (
<Provider store={store} key="provider">
{component}
</Provider>);
}
}
}
const dest = document.getElementById('content');
ReactDOM.render(
<AppProvider />,
dest
);
// const persistor = persistStore(store, {}, () => { this.rehydrated = true; });
This is the main App.js component in this project.
So when I access localhost/confirm, I don't get a 404 not found page but I get an empty page. Earlier I've tried to console.log a few things but it didn't work either. I've been working on this my whole day and I didn't manage to make it work. Does someone know what am I doing wrong?
Did you try to add / in Route path?
<Route path="/confirm"
You need to add / before every route. That's why it is not getting the component you want. So modify your code by adding / like the following
<Route path="/confirm" component={ConfirmMail}/>
And another thing that I recommend you to do is enclose your routers inside <Switch></Sitch>. If the URL is /confirm, then all routes below it will be rendered. This is by design, allowing us to compose s into our apps in many ways, like sidebars and breadcrumbs, bootstrap tabs, etc.
Occasionally, however, we want to pick only one to render. If we’re at /confirm we don’t want to also match /:orgName If so you will end up with 404 error.
Here’s how to do it with Switch:
return (
<Switch>
<Route path="/" component={App}/>
<Route path="confirm" component={ConfirmMail}/> //THIS IS THE COMPONENT I'M TRYING TO ACCESS
{ /* Home (main) route */ }
<IndexRoute component={Home}/>
{ /* Routes requiring login */ }
<Route onEnter={requireLogin}>
<Route path="projects/create" component={TaggerCreate}/>
<Route path="projects/edit" component={TaggerEdit}/>
<Route path="projects/:orgName/create" component={TaggerCreate}/>
<Route path="projects/:orgName/import" component={TaggerImport}/>
<Route path="projects/:orgName/:projectName/edit" component={TaggerEdit}/>
<Route path="projects/:orgName/:projectName/keybind" component={TaggerKeyBind}/>
</Route>
{ /* Dataturks tool */}
<Route path="projects/login" component={TaggerLogin}/>
<Route path="projects/import" component={TaggerImport}/>
<Route path="projects/space" component={TaggerSpace}/>
<Route path="projects/stats" component={TaggerStats}/>
<Route path="projects/export" component={TaggerExport}/>
<Route path="projects" component={TaggerProjects}/>
<Route path="projects/add" component={TaggerAdd}/>
<Route path="projects/overview" component={TaggerOveriew}/>
<Route path="projects/visualize" component={TaggerVisualize}/>
<Route path="projects/errors" component={TaggerError}/>
<Route path="projects/:orgName" component={TaggerOrg} />
<Route path="projects/:orgName/:projectName" component={TaggerOrgProject} />
<Route path="projects/:orgName/:projectName/space" component={TaggerSpace}/>
<Route path="projects/:orgName/:projectName/export" component={TaggerExport}/>
<Route path="projects/:orgName/:projectName/overview" component={TaggerOveriew}/>
<Route path="projects/:orgName/:projectName/visualize" component={TaggerVisualize}/>
<Route path="projects/:orgName/:projectName/contributors" component={TaggerContributors}/>
{ /* Catch all route */ }
<Route path="*" component={NotFound} status={404} />
</Switch>
);

Unable to connect ReactJS App with google analytics

I am trying to connect my personal website made using ReactJS to Google Analytics. I have followed this tutorial but I am still not able to see an active user (when I access the site on local host or when I deploy it using netlify).
Here is my app.js:
import React, {useEffect} from 'react';
import Courses from './containers/Courses/Courses';
import Home from './containers/Home/Home';
import {Route, Switch, Redirect} from 'react-router-dom';
import Layout from './hoc/Layout/Layout';
import About from './containers/About/About';
import ContactPage from './containers/ContactPage/ContactPage';
import Projects from './components/Projects/Projects';
import ReactGa from 'react-ga';
const App = () => {
useEffect(() => {
document.title = "Dhruv Mittal";
ReactGa.initialize('UA-XXXXXXXXX-X');
//Report page view
ReactGa.pageview(window.location.pathname + window.location.search);
}, []);
let routes = (
<Switch>
<Route path="/about" component={About}/>
<Route path="/projects" component={Projects}/>
<Route path="/courses" component={Courses}/>
<Route path="/contact" exact component={ContactPage}/>
<Route path="/" component={Home}/>
<Redirect to='/'/>
</Switch>
);
return (
<div>
<Layout>
{routes}
</Layout>
</div>
);
}
export default App;
You are not listening to the location changes. Try this way. Add a component called GAListener, which listen to the location changes of history object.
GaListener.js
import React from 'react';
import ReactGA from 'react-ga';
import { withRouter } from 'react-router-dom';
class GAListener extends React.Component {
componentDidMount() {
ReactGA.initialize("UA-XXXXXXXXX-X");
this.sendPageView(this.props.history.location);
this.props.history.listen(this.sendPageView);
}
sendPageView = location => {
ReactGA.set({ page: location.pathname });
ReactGA.pageview(location.pathname);
};
render() {
return this.props.children;
}
}
export default withRouter(GAListener);
Now wrap your Route components inside GAListener component as follows.
App.js
const App = () => {
let routes = (
<GAListener>
<Switch>
<Route path="/about" component={About}/>
<Route path="/projects" component={Projects}/>
<Route path="/courses" component={Courses}/>
<Route path="/contact" exact component={ContactPage}/>
<Route path="/" component={Home}/>
<Redirect to='/'/>
</Switch>
</GAListener>
);
return (
<div>
<Layout>
{routes}
</Layout>
</div>
);
}
export default App;

react redirect not working when some routes are inside a custom component

Live preview
I have a simple routing stragary.
for /login -> show LoginPageContainer
for /register -> show LoginPageContainer again
for / -> redirect to /login
for * -> show NotFoundPage
If all routes are at same level everything works fine.
<BrowserRouter>
<Switch>
{/*<App />*/}
<Route path={'/login'} component={LoginPageContainer}/>
<Route path={'/register'} component={LoginPageContainer}/>
<Route exact path="/">
<Redirect to="/login" />
</Route>
<Route path='*' component={NotFoundPage} />
</Switch>
</BrowserRouter>
But If login and register routes are inside App component, / and * routes show nothing.
Index.js
<Switch>
<App />
{/*<Route path={'/login'} component={LoginPageContainer}/>*/}
{/*<Route path={'/register'} component={LoginPageContainer}/>*/}
<Route exact path="/">
<Redirect to="/login" />
</Route>
<Route path='*' component={NotFoundPage} />
</Switch>
App.js
render() {
const { alert } = this.props;
return (
<div className="container">
<div className="col-sm-8 col-sm-offset-2">
<Route path={'/login'} component={LoginPageContainer}/>
<Route path={'/register'} component={LoginPageContainer}/>
</div>
</div>
);
}
Full code
index.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { store } from './helpers';
import { App } from './App';
import { configureFakeAPI } from './helpers';
import {BrowserRouter, Switch} from "react-router-dom";
import { Router, Route, Redirect } from 'react-router-dom';
import {NotFoundPage} from "./components/NotFoundPage";
import LoginPageContainer from "./components/LoginPage";
configureFakeAPI();
render(
<Provider store={store}>
<BrowserRouter>
<Switch>
<App />
{/*<Route path={'/login'} component={LoginPageContainer}/>*/}
{/*<Route path={'/register'} component={LoginPageContainer}/>*/}
<Route exact path="/">
<Redirect to="/login" />
</Route>
<Route path='*' component={NotFoundPage} />
</Switch>
</BrowserRouter>
</Provider>,
document.getElementById('app')
);
App.js
import React from 'react';
import {Router, Route, Switch} from 'react-router-dom';
import { connect } from 'react-redux';
import { PrivateRoute } from './PrivateRoute.js';
import { history } from './helpers';
import { alertActions } from './actions';
import { HomePage } from './components/HomePage';
import LoginPageContainer from './components/LoginPage';
import { RegisterPage } from './components/RegisterPage';
import './styles.css';
export class App extends React.Component {
constructor(props) {
super(props);
const { dispatch } = this.props;
history.listen((location, action) => {
});
}
render() {
const { alert } = this.props;
return (
<div className="container">
<div className="col-sm-8 col-sm-offset-2">
<Route path={'/login'} component={LoginPageContainer}/>
<Route path={'/register'} component={LoginPageContainer}/>
</div>
</div>
);
}
}
function mapStateToProps(state) {
const { alert } = state;
return {
alert
};
}
export default connect(mapStateToProps)(App);
The routes you mentioned show nothing, I believe, because <Switch/> only expects <Route/> inside of it, and is looking to match the current location to those routes. But you're feeding it <App/> which makes it always return that and stop.
You either need to put <App/> itself in a <Route/> inside of the switch or take it outside, and maybe use another <Switch/> for the nested routes in the component.

Getting started with React Router

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
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.
Hi #Mel I faced similar issue a few days back, and i resolved it as following:
In your index.html, check that your id is app and not root.
Modify your app.js to have:
const jsx = (
<Provider store={store}>
<BrowserRouter>
<AppRouter />
</BrowserRouter>
</Provider>
);
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! ;)
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}
)
}
}
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);

Sub routes at react router 4

I am having problems dividing my application and using several routers. I have a main router where it handles several small applications and in each mini application I want to manage its opportune routes. What am I failing?
What I want to do is when I receive the data of the request, redirect me to a new screen but I can not get it. Can anybody help me? Thank you
Example https://stackblitz.com/edit/react-c2tkgf?file=Hello.js
Routes.js
import { BrowserRouter } from 'react-router-dom'
import React from 'react'
import { Switch, Route } from 'react-router-dom'
import { AuthenticatedRoute } from 'components/authenticated-route'
import Clients from 'components/clients'
import { Login } from 'components/login'
import Home from './Home/Home'
const Routes = () => {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />} />
<Route exact path="/clients" component={Clients} />
<Route exact path="/login" component={Login} />} />
</Switch>
</BrowserRouter>
)
}
export default Routes
Clients.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import Dashboard from './Dashboard/Dashboard'
import { Redirect, Route, Switch } from 'react-router-dom'
class Clients extends Component {
render() {
return (
<div>
<SearchCustomers />
{this.props.customer.token ? (
<div>
<Switch>
<Route path={`/clients:${this.props.customer.id}/dashboard`} component={Dashboard} />
</Switch>
<Redirect to={`/clients:${this.props.customer.id}/dashboard`} />
</div>
) : null}
</div>
)
}
}
const mapStateToProps = state => {
return {
customer: state.customer,
}
}
export default connect(mapStateToProps)(Clients)
In your Routes component you have:
<Route exact path="/clients" component={Clients} />
<Route exact path="/login" component={Login} />} />
since you have exact on there, those components will only be rendered when at exactly /clients or /login. in your built components, once you change the path, your parent component no longer renders, therefore nothing inside those components will render. remove the exact from your Routes:
<Rout path="/clients" component={Clients} />
<Rout path="/login" component={Login} />} />

Resources