Miha Šušteršič
Miha Šušteršič

Reputation: 10052

React Router always displaying IndexRoute

This is my main app file:

import React from 'react';
import { render } from 'react-dom';
import { browserHistory, Router, Route, IndexRoute } from 'react-router';

// Components
import Main from './components/core/Main.component';
import NotFound from './components/core/NotFound.component';
import About from './components/About.component';
import TeaTimer from './components/TeaTimer.component';

// App css
require('style!css!sass!applicationStyles');

render(
    (<div>
      <Router history={browserHistory}>
        <Route component={Main} path="/">
          <IndexRoute component={TeaTimer} />
          <Route component={About} path="/about"/>
        </Route>
        <Route component={NotFound} path="*"/>
      </Router>
    </div>),
    document.querySelector('#app')
);

This is my Main component:

import React, { Component } from 'react';

class Main extends Component {
  render() {
    return (
        <div>
            {this.props.children}
        </div>
    )
  }
}

Main.propTypes = {
  children: React.PropTypes.object
}

export default Main;

This is my express server setup:

var express = require('express');

// Create our app
var app = express();
const PORT = process.env.PORT || 3000;

app.use(function (req, res, next){
  if (req.headers['x-forwarded-proto'] === 'https') {
    res.redirect('http://' + req.hostname + req.url);
  } else {
    next();
  }
});

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

app.listen(PORT, function () {
  console.log('Express server is up on port ' + PORT);
});

Now when I open the browser and go to http://localhost:3000 I get the TeaTimer component. Same for http://localhost:3000/#/, same for http://localhost:3000/#/about, same for an undefined route - http://localhost:3000/#/sdnaipwnda[j.

But when I go to http://localhost:3000/about I get:

Cannot GET /about

What am I doing wrong?

If you need more info please ask and I will add it to the question, or checkout this git repo.

Upvotes: 2

Views: 1247

Answers (3)

Khalid Azam
Khalid Azam

Reputation: 1643

no need to have / inside about path.

render(
    (<div>
      <Router history={browserHistory}>
        <Route component={Main} path="/">
          <IndexRoute component={TeaTimer} />
          <Route component={About} path="about" />
        </Route>
        <Route component={NotFound} path="*" />
      </Router>
    </div>),
    document.querySelector('#app')
);

Upvotes: 0

Stefan Dragnev
Stefan Dragnev

Reputation: 14473

OK, this one is straightforward. You're simply using the wrong history. You need hashHistory if you want to have hash-based, i.e. /#/about and such, routes.

import {Router, hashHistory} from 'react-router' ... <Router history={hashHistory}> ...

If you DON'T want a hash-based history, but would rather like regular-looking URL's, like /about and such, then you DO need browserHistory. However, in this case you MUST make sure that your web server serves the same index.html for all route-like URL's. This is explained in the react-router' documentation. You need to add something like this towards the end of your express server's routing configuration:

// handle every other route with index.html, which will contain // a script tag to your application's JavaScript file(s). app.get('*', function (request, response){ response.sendFile(path.resolve(__dirname, 'public', 'index.html')) }) The above code assumes that your index.html file lies in public/, so you might need to change the arguments to path.resolve.

I actually prefer returning index.html only for URL's that don't have an extension. This way you prevent your index.html being served as a .png or .js whenever the requested resource is missing and you get a meaningful 404 instead.

app.get('*', function (request, response){ if (request.path.match(/\/[^\/.]*$/)) { response.sendFile(path.resolve(__dirname, 'public', 'index.html')) } })

Upvotes: 1

Amir-Mousavi
Amir-Mousavi

Reputation: 4561

remove / from path

<Route component={About} path="about"/>

remove

Main.propTypes = {
  children: React.PropTypes.object
}

anyway children are passed as props by default

Upvotes: 0

Related Questions