1

I am trying to get nested routes working on React Router v4. I am referring to this page https://reacttraining.com/react-router/web/guides/quick-start

So how they do nested route is this

import React from 'react'
import {
    BrowserRouter as Router,
    Route,
    Link
} from 'react-router-dom'

const BasicExample = () => (
  <Router>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/topics">Topics</Link></li>
          </ul>

      <hr/>

      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
    </div>
  </Router>
)

const Home = () => (
  <div>
    <h2>Home</h2>
  </div>
)

const About = () => (
  <div>
    <h2>About</h2>
  </div>
)

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <ul>
      <li>
        <Link to={`${match.url}/rendering`}>
          Rendering with React
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/components`}>
          Components
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/props-v-state`}>
          Props v. State
        </Link>
      </li>
    </ul>

    <Route path={`${match.url}/:topicId`} component={Topic}/>
    <Route exact path={match.url} render={() => (
      <h3>Please select a topic.</h3>
    )}/>
  </div>
)

const Topic = ({ match }) => (
  <div>
    <h3>{match.params.topicId}</h3>
  </div>
)

export default BasicExample

This works obviously but I want to change it into a class format.

So I have tried below

index.js

render((
        <Router>
            <div>
                <Route path="/" component={App}/>
            </div>
        </Router>
    ), document.getElementById('root')
);

App.js

class App extends Component {
    render() {
        return (
            <div className="container">
                <header>
                    <span className="icn-logo"><i className="material-icons">code</i></span>
                    <ul className="main-nav">
                        <li><Link to="/">Home</Link></li>
                        <li><Link to="/about">About</Link></li>
                        <li><Link to="/teachers">Teachers</Link></li>
                        <li><Link to="/courses">Courses</Link></li>
                    </ul>
                </header>
                <Route exact path="/" component={Home}/>
                <Route path="/about" component={About}/>
                <Route path="/teachers" component={Teachers}/>
                <Route path="/courses" component={Course}/>
            </div>
        );
    }
}

export default App;

The problem is that when I click on the links, it routes to the correct url and it works but when I type in the url myself, it gives cannot GET /about and so on even though they are all rendering to same url - whether I click on the links or whether i type them myself. I am thinking App route is not being rendered except at root which I don't understand why. Does anyone know why that might be?

Also, how do I convert my code so that I can take in the match parameter like the first example code? So in topics it is taking match object as a parameter and I am guessing that is some kind of reference to its previous url

SOLUTIONS

Okay I'm going to provide solutions here as a lot of video based React Router tutorials do not cover React Router v4. I hope the noobs who are struggling with the new React Router can get help from this answer.

So basically you have to be able to differentiate client side route with the asset request and webpack-dev-server provides a perfect option for this.

All you have to do is add

devServer: {
    port: 3000,
    historyApiFallback: {
        index:'index.html'
    }
}

to the webpack.config.js which will always point to index.html when there is no response from the server

This is my reference. Might be useful to read it https://jaketrent.com/post/pushstate-webpack-dev-server/

1 Answer 1

3

This is generally a server problem rather than anything in your client-side code. If you are using express with static serving:

app.use(express.static('build'));

Then if there isn't a file in the directory build, or another express route that matches e.g. /about then express won't respond with anything.

You need to add a catch all route to express in addition to the static middleware above - it must be after it in your route definitions though.

app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname, '../build', 'index.html'));
};

This is a wildcard route, so anything that hasn't been matched by the static middleware will be sent index.html. Once that lands in your browser then react-router will take over and load the correct components.

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

5 Comments

but that's node... I am using react and building it with webpack. So it should still work shouldn't it? The example code works without express
If you are getting the error Cannot GET /about then you have a server running that is looking for a (server-side) route handler that matches /about, and not finding one. This is the expected behaviour when you type in the URL.
no it's still not working even when I route everything to index.html with server. It goes path is not defined.
@DaurenAkilbekov Thank you so much for that. I spent the entire day trying to solve this problem but you've done it for me!

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.