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);
Related
I am building an E-Commerce MERN Stack Web Application. The loading time of my Home Page as tested by Lighthouse is more than 12s.
I have hence posted the App.js file and my main main homepage.js file.
How can I implement code splitting on my homepage.js file (using Lazy-Suspense method o any other)?
homepage.js
import React, { Component } from 'react';
import Header from '../header/header';
import About from '../about/about';
import Services from '../services/services';
import Footer from '../footer/footer';
import Navbar from '../navbar/navbar';
export default class Homepage extends Component {
state = {
response: '',
email: '****.com',
password:'****',
message:'',
};
render() {
let loggedIn = this.props.loggedIn;
console.log(loggedIn)
return (
<div className="App">
<Navbar />
<Header resumeData={{name:this.state.email,}}/>
<Services resumeData={{name:this.state.email,}}/>
<About resumeData={{name:this.state.email,}}/>
<Footer resumeData={{name:this.state.email,}}/>
</div>
);
}
}
App.js
import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Homepage from './components/homepage/homepage';
import LogIn from './components/login/login';
import SignUp from './components/signup/signup';
import Reset from './components/reset/reset';
import Account from './components/account/account';
import Verify from './components/verify/verify';
import Shop from './components/shop/shop';
import Cart from './components/cart/cart';
import Checkout from './components/cart/checkout';
import Admin from './components/admin/admin';
import Order from './components/order/order';
import Subscription from './components/order/subscription';
import Subscribe from './components/subscribe/subscribe';
class App extends Component {
render() {
return (
<BrowserRouter>
<Switch>
<Route path="/" component={Homepage} exact/>
<Route path="/shop" component={Shop} />
<Route path="/cart" component={Cart} />
<Route path="/checkout:what" component={Checkout} />
<Route path="/subscribe" component={Subscribe} />
<Route path="/order:oId" component={Order} />
<Route path="/subscription:sId" component={Subscription} />
<Route path="/login" component={LogIn}/>
<Route path="/admin" component={Admin}/>
<Route path="/signup" component={SignUp}/>
<Route path="/reset" component={Reset}/>
<Route path="/account" component={Account}/>
<Route path="/verify/:token" component={Verify}/>
</Switch>
</BrowserRouter>
);
}
}
export default App;
this how you code split your react js app:
import React,{lazy,Suspense} from 'react'
const Child = lazy(()=>import('./ChildComponent'))
const Parent = ()=> <Suspense fallback={<Loader/>}><Child/></Suspense>
here is full detailed explanation : React Code splitting
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.
I am trying to access my store from every component page I have, so I followed the following tutorial in order to connect React Router & MobX.
http://frontendinsights.com/connect-mobx-react-router/
However, I am facing a problem at The MobX way – Provider component.
This is the code exmaple:
import { Provider } from 'mobx-react';
import usersStore from './stores/usersStore';
import itemsStore from './stores/itemsStore';
const stores = { usersStore, itemsStore };
ReactDOM.render(
<Provider {...stores}>
<Router history={history}>
<Route path="/" component={App}>
</Route>
</Router>
</Provider>,
document.getElementById('app')
);
I tried to do the same in index.js
import React from 'react'
import { render } from 'react-dom'
import { Router, hashHistory, Route, IndexRedirect } from 'react-router'
import App from './webapp/App'
import Home from './components/pages/Home'
import Dogs from './components/pages/Dogs'
import Cats from './components/pages/Cats'
import Provider from 'mobx-react'
import RootStore from './webapp/stores'
const store = RootStore
render((
<Provider rootStore={store}>
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRedirect to="/home" />
<Route path="/home" component={Home}/>
<Route path="/dogs" component={Dogs}/>
<Route path="/cats" component={Cats}/>
</Route>
</Router>
</Provider>
), document.getElementById('app'))
However, because of <Provider/>, I am getting an error:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
Why am I getting that? It should work doesn't it?
Thanks for any help !
If it's a web app, react-router-dom should be used.
Here is the correct way to inject store with Provider https://github.com/mobxjs/mobx-react#observer
I wrote a solution for your code without using decorator, so it supports create-react-app:
import React, { Component } from 'react';
import { Provider, Observer } from 'mobx-react';
import { observable } from 'mobx';
import { BrowserRouter, Switch, Route, Link, Redirect } from 'react-router-dom';
const myStore = observable({
home: 'Home',
cat: 'Cat',
});
const Home = () => (
<Observer
inject={stores => ({ myStore : stores.myStore })}
render={props => (<section><h1>{props.myStore.home}</h1></section>)}
/>
);
const Cat = () => (
<Observer
inject={stores => ({ myStore : stores.myStore })}
render={props => (<section><h1>{props.myStore.cat}</h1></section>)}
/>
);
class App extends Component {
render() {
return (
<BrowserRouter>
<Provider myStore={myStore}>
<div className="App">
<header className="App-header">
<nav>
<ul>
<li><Link to="/home">HOME</Link></li>
<li><Link to="/cat">CAT</Link></li>
</ul>
</nav>
</header>
<Switch>
<Route path='/home' exact component={Home} />
<Route path='/cat' exact component={Cat} />
<Redirect from="/" to="/home" />
</Switch>
</div>
</Provider>
</BrowserRouter>
);
}
}
export default App;
All the components are in App.js file. There is no change in default index.js from create-react-app.
Note:
The another way to doing this, it's to simply create a singleton class for the store and use export default new Store() to make it available to all components. The class itself doesn't have to be observable, but its properties do.
I am learning redux with react and hit a mental roadblock, I have the following entry index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Redirect, Route} from 'react-router-dom';
import {Provider} from 'react-redux';
import store from './store';
import Bootstrap from 'bootstrap/dist/css/bootstrap.css';
import Main from './components/front/Main';
import Login from './components/front/Login';
import Home from './components/front/Home';
import Register from './components/front/Register';
import Forgot from './components/front/Forgot';
import Verify from './components/front/Verify';
import Dashboard from './components/back/Dashboard';
import './css/app.css';
import Auth from './components/Auth';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
Auth.isLogged ? ( //<-need to get props here
<Component {...props}/>
) : (
<Redirect to={{
pathname: '/',
state: { from: props.location }
}}/>
)
)}/>
)
const App = () => (<BrowserRouter>
<div>
{/* PUBLIC */}
<Route path={'/'} exact component={Home}/>
<Route path={'/login'} component={Login}/>
<Route path={'/register'} component={Register}/>
<Route path={'/forgot'} component={Forgot}/>
<Route path={'/verify'} component={Verify}/>
{/* PRIVATE */}
<PrivateRoute path="/dashboard" component={Dashboard}/>
</div>
</BrowserRouter>);
ReactDOM.render(<Provider store={store}><App/></Provider>, document.getElementById('root'));
Overall redux works, the only problem is in this file, as I am not exporting anything, I can't get connect to work.
Ideally Auth.isLogged should be either true or false based on isAuthenticated prop, but I can't get the value passed in any way to the entry index.js
import React from 'react';
import { connect } from 'react-redux';
#connect((store) => {
return {isAuthenticated: store.auth.isAuthenticated, authenticating: store.auth.authenticating};
})
export default class Auth extends React.Component {
//Can't get anything from here to index.js
}
Please any help would be greatly appreciated!
If I understand correctly, you’re trying to provide context of store.auth.isAuthenticated to PrivateRoute.
If you declare App in its' own file you can connect it to the store and then pass the value of isAutenticated to your PrivateRoute component
//App.js
import React, { Component } from 'react'
import { withRouter, Switch, Route } from 'react-router-dom'
import { connect } from 'react-redux'
import PrivateRoute from 'components/PrivateRoute'
#withRouter
#connect(store => ({
isAuthenticated: store.auth.isAuthenticated,
authenticating: store.auth.authenticating
}))
class App extends Component {
render() {
const { isAuthenticated } = this.props
return (
<span>
{/* PUBLIC */}
{ !isAuthenticated &&
<Switch>
<Route path={'/'} exact component={Home}/>
<Route path={'/login'} component={Login}/>
<Route path={'/register'} component={Register}/>
<Route path={'/forgot'} component={Forgot}/>
<Route path={'/verify'} component={Verify}/>
</Switch>
}
{/* PRIVATE */}
{ isAuthenticated &&
<PrivateRoute
isAuthenticated={isAuthenticated}
path="/dashboard"
component={Dashboard}
/>
}
</span>
)
}
}
export default App
For readability sake you could make this change in index.js
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
)
You may or may not need to wrap connect(App) inside of withRouter, but the way I was handling my routing made this part necessary.
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!