5

I'm new to React and React Router. I'm using React Router v4 and following a tutorial based on previous versions - but I made it work (using some stuff found on SO and some stuff on the react router v4 docs).

There is one thing though that is bothering me.

I have a url http://localhost:3000/#/bugs, which basically loads a list of all my bugs. But I also have possible urls like http://localhost:3000/#/bugs?priority=low&status=open which loads a specific set of urls.

The urls themselves work and do the job as expected.

The werid thing is that whenever I type http://localhost:3000/#/bugs?priority=low&status=open (or any params), the component do their jobs but the URL address bar shows http://localhost:3000/#/bugs (although the rendering shows everything related to priority and status shown).

Somehow, the URL location bar is changed but I don't understand why.

Here is my App.js

import React from 'react';
import ReactDOM from 'react-dom';
import {BugList} from './BugList';
import {Redirect} from 'react-router';
import {HashRouter as Router, Route} from 'react-router-dom';



const NoMatch = React.createClass({
    render : function (){
        return(
            <h2>This path does not exist</h2>
        );
    }
});


ReactDOM.render(
    (
        <Router>
            <div>
                <Route path='/bugs' component={BugList}/>
                <Route path='/bugs/priority/:priority' component={BugList}/>    
                <Redirect from='/' to="/bugs" />
                <Route path="*" component={NoMatch} />
            </div>
        </Router>
    ),
    document.getElementById('main')
);

Thanks in advance.

EDIT 12th of April. Despite of the precious help of someone below, this is still not solved. I tried using Switch inside a Router but it doesn't work at all (nothing is shown). So the problem is still happening, and this is the current state of my App.js, using react-15.5.3, react-dom-15.5.3, react-router-4.0.0 and react-router-dom-4.0.0....

import React from 'react';
import ReactDOM from 'react-dom';
import {BugList} from './BugList';
import BugEdit from './BugEdit';
import {Redirect} from 'react-router';
import {HashRouter as Router, Route} from 'react-router-dom';

const NoMatch = React.createClass({
    render : function (){
        return(
            <h2>This path does not exist</h2>
        );
    }
});

ReactDOM.render(
    (
        <Router>
            <div>
                <Redirect from='/' to="/bugs" />
                <Route path='/bugs' component={BugList}/>
                <Route path='/bug/:id' component={BugEdit}/>
                <Route path="*" component={NoMatch} />
            </div>
        </Router>
    ),
    document.getElementById('main')
);
Brandon Culley
  • 5,219
  • 1
  • 28
  • 28
nicolasdaudin
  • 302
  • 1
  • 4
  • 15

3 Answers3

3

The problem is that even if you enter the URL with query this URL matches Redirect path (since it's just / any URL matches this pattern) so the redirection to /bugs occurs. You have to use Switch (remember to import it) to render only the first <Route> or <Redirect> that matches the URL:

<Router>
     <Switch>
        <Route path='/bugs' component={BugList}/>
        <Redirect from='/' to="/bugs" />
        ...
   </Switch>
</Router>

The problem occured only on page load and not on re-entering the URL because your routing is based on hashes and the browser doesn't reload page when only hash part changes.
Please note that Redirect component in React-Router v4 performs redirection only when it's rendered - it doesn't set up permanent redirection rule so in your case redirection works only on page load. If you'd like your app to always redirect given URL you'd have to define Route for URL you'd like to redirect from and render Redirect:

<Route path='/oldUrl' render={() => (
    <Redirect to="newUrl" />
)}/>

Furthermore, React-Router v4 is quite different from v3 so I don't recommend using v3 tutorials - it doesn't make sense.

Bartek Fryzowicz
  • 6,464
  • 18
  • 27
  • Cheers. Now that you say it, it's pretty obvious but you just unblocked me! Thanks a lot! – nicolasdaudin Apr 03 '17 at 14:28
  • Actually I got it wrong. It still has the same behavior. I load localhost:3000/#/bugs?priority=low&status=open and it ignores this and goes to http://localhost:3000/#/bugs automatically. – nicolasdaudin Apr 03 '17 at 14:59
  • Ok, so next thing is that your URL doesn't match route `path` pattern because you pass `priority` as query - your URL should be like this: `localhost:3000/#/bugs/priority/low?status=open`. Your Route path expects `priority` as path segment not as query – Bartek Fryzowicz Apr 03 '17 at 15:09
  • I made some changes to my routing because I've decided to use query parameters (as per my example URL), so now it's ` ` But it still fails. The weird thing is that it only fails on the first load of the React components. I mean if I open a new tab and put the url localhost:3000/#/bugs?priority=low&status=open , it redirects me to localhost:3000/#/bugs. But then if in the same tab I re-enter localhost:3000/#/bugs?priority=high&status=closed (for example), the URL stays – nicolasdaudin Apr 03 '17 at 15:14
  • Thanks! Still not working, I get this error :Warning: Failed context type: The context `router` is marked as required in `Switch`, but its value is `undefined`. in Switch` – nicolasdaudin Apr 08 '17 at 07:51
  • The above code must be placed inside `Router` component - I've updated code sample. – Bartek Fryzowicz Apr 08 '17 at 08:09
  • Thanks! But it doesn't work. Actually, now the app itself doesn't work anymore when everything is inside `Router` component. If I remove the `Switch` and replace it by `div`, my app works (except the redirection, still bugging of course) – nicolasdaudin Apr 09 '17 at 18:28
1

Building on what Bartek said: if you use Switch, it will go directional from top to bottom and render the first hit, since you moved your redirect to the first position it will always hit that first and then not go to the other routes. Which is why your Switch should look like this imho (untested):

<Router>
    <Switch>
        <Route path='/bugs' component={BugList}/>
        <Route path='/bug/:id' component={BugEdit}/>
        <Redirect from='/' to="/bugs" />
        <Route path="*" component={NoMatch} />
    </Switch>
</Router>
Fabian Bosler
  • 2,310
  • 2
  • 29
  • 49
0

I know its 04/2020, but this will fix your issue.

    <Switch>
        <Route path='/bug/:id' component={BugEdit}/>
        <Route path='/bugs' component={BugList}/>
        <Redirect from='/' to="/bugs" />
        <Route path="*" component={NoMatch} />
    </Switch>
</Router>```
Alex Gontcharov
  • 111
  • 2
  • 8