1

I am switching from react-router 3.x to 4.x and I am not able to render nested routes.

I bootstrapped an application using create-react-app

index.js file

import React from 'react';
import ReactDOM from 'react-dom';
import Routes from './routes';
import './index.css';

ReactDOM.render(<Routes />, document.getElementById('root'));

routes.js file

import React from 'react';
import _ from 'lodash';
import {
  BrowserRouter as Router,
  Route,
} from 'react-router-dom';
import { dojoRequire } from 'esri-loader';
import EsriLoader from 'esri-loader-react';

import App from './components/App';
import Home from './components/Home';

/**
 * Helper component to wrap app
 */
class AppWrapper extends React.Component {
  /**
   * Util function to render the children
   * Whenever a state change happens in react application, react will render the component again
   * and we wish to pass the updated state to the children as props
   */
  renderChildren() {
    const {children} = this.props;
    if (!children) {
      return;
    }

    return React.Children.map(children, c => React.cloneElement(c, _.omit(this.props, 'children'), { }));
  }

  render() {
    const child = this.renderChildren();
    return (
      <App {...this.props}>
        {child}
      </App>
    );
  }
}

/**
 * Root Loader component to load esri api
 */
class LoaderComponent extends React.Component {

  constructor(props) {
    super(props);
    this.state = { loaded: false };
  }

  /**
   * Callback fired when arc GIS api is loaded
   * Now load the requirejs modules using dojorequire
   */
  esriReady() {
    dojoRequire(['esri/Map', 'esri/views/MapView'], (Map, MapView) => {
      this.setState({ Map, MapView, loaded: true });
    });
  }

  render() {
    const options = {
      url: 'https://js.arcgis.com/4.3/',
    };
    return (
      <div>
        <EsriLoader options={options} ready={this.esriReady.bind(this)} />
        <AppWrapper {...this.state}>
          <Route exact path="/home" component={Home} />
        </AppWrapper>
      </div>
    );
  }
};

const Routes = (props) => (
  <Router {...props}>
    <Route exact path="/" component={LoaderComponent} />
  </Router>
);

export default Routes;

App and home components are simple div tags that renders <div>Hello world App</div> and <div>Hello world Home</div>

The App component renders perfectly, but when I navigate to http://localhost:3000/home component I see an empty page.

What I would like to do is

When the user launched the app the user should be redirected to /home and I would like to define two additional routes for App Component

<Route exact path="/a" component={A} />
<Route exact path="/b" component={B} />

Currently I am not able to redirect to /home on app load and not able to define nested routes for App Component.

NOTE: This above code was working fine for react-router version 3.x. To redirect on page load I would use IndexRedirect.

I already had a look at this and this question and I tried all possible solutions in those questions but none is working.

I would like to have all the route handling in routes.js file.

Community
  • 1
  • 1
Ritesh
  • 93
  • 7

2 Answers2

3

You could achieve such routing with Switch and Redirect:

import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';

import {LoaderComponent, AppWrapper , Home, A, B} from './mycomponents';


const routes = (
  <LoaderComponent>
    <AppWrapper>
      <Switch>
        <Route exact path='/' render={() => <Redirect to='/home' />} />
        <Route exact path='/home' component={Home} />
        <Route exact path='/a' component={A} />
        <Route exact path='/b' component={B} />
      </Switch>
    </AppWrapper>
  </LoaderComponent>
);

export default routes;

And use the routes.js file something like this:

import React from 'react';
import {render} from 'react-dom';
import {Router} from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';

import routes from './routes';


const history = createHistory();

const App = () =>
  <Router history={history}>
    {routes}
  </Router>;

render(<App />, document.getElementById('root'));
Karolis Šarapnickis
  • 1,257
  • 18
  • 20
  • You missed the `LoaderComponent`. It is required as I have to load some external api. – Ritesh May 15 '17 at 08:48
  • All the 3 components, Home, A, B should follow the hierarchy. `LoaderComponent -> App -> Home/A/B` – Ritesh May 15 '17 at 08:50
  • I updated my answer with the hierarchy. Since everything in react-router-4 is a component, you can define routes wherever you want, not only in 1 file (`routes.js`) if this isn't the structure you can organize your code. – Karolis Šarapnickis May 15 '17 at 09:40
1

Hey I have implemented react-router-v4, for a simple sample project. here is the github link : How to Implement the react-router-v4. please go through it. very simple.

to run : clone it and hit npm install. hope this will help to you.

Chanaka Anuradh Caldera
  • 4,280
  • 7
  • 34
  • 61