简体   繁体   中英

Nested Routes with React Router v4 - Solutions

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/

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 eg /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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM