2

When I navigate between pages using the navbar and the buttons, the URL on the browser changes normally. But once I try to modify the URL manually, it does not work !

Example 1

  • Step 1 : I open localhost:3000
  • Step 2 : I click on Athletes to go to localhost:3000/Athletes
  • Step 3 : I choose an athlete to go to localhost:3000/Athletes/2/AthleteSessions/
  • Step 4 : I change the URL manually to localhost:3000/Athletes then I choose an athlete, I'm redirected to localhost:3000/Athletes/2/AthleteSessions/ fine until now, but when I modify the URL to put localhost:3000/Athletes/ with a slash then I choose an athlete it does not work and I'm redirected to localhost:3000/Athletes/Athletes/2/AthleteSessions/

Example 2

  • Step 1, 2 and 3 are the same as the first example.
  • Step 4 : I choose an AthleteSession to go to localhost:3000/Athletes/2/AthleteSessions/1/TrainingSession/ it works fine, but when I try to go back to previous page by modifying manually the URL localhost:3000/Athletes/2/AthleteSessions then I choose an AthleteSession again, it does not work and I'm redirected to localhost:3000/Athletes/2/1/TrainingSession/

App.js

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

<Route path="/Athletes" exact component={Athletes} />
<Route path="/Athletes/:id/AthleteSessions" exact component={AthleteSessions} />
<Route path="/Athletes/:athleteId/AthleteSessions/:athleteSessionId/TrainingSession"
       exact component={AthleteTrainingSession} />

Index.js

import { BrowserRouter as Router } from "react-router-dom";

render( <Router> <App /> </Router>, document.getElementById("root") );

Athletes.js

onClick={() => {
  this.props.history.push({
    pathname:
      "Athletes/" + ath.AthleteId + "/AthleteSessions/",
  });
}}

AthleteSessions.js

passedAthleteId = this.props.match.params.id;

onClick={() => {
  this.props.history.push({
    pathname:
      athSess.AthleteSessionId + "/TrainingSession/",
  });
}}
Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
wAeLoS
  • 35
  • 1
  • 5
  • 1
    Here are the instructions on how you create a StackOverflow snippet: https://stackoverflow.blog/2014/09/16/introducing-runnable-javascript-css-and-html-code-snippets/ – Wezelkrozum May 30 '20 at 14:48
  • 1
    I created a git repo with the code you need to see : https://github.com/Waelos/react-url-manual-modification – wAeLoS May 30 '20 at 18:47
  • 1
    Thanks @AjeetShah :-) – wAeLoS May 30 '20 at 20:11
  • I forked your repo and raised pull request. [Forked repo](https://github.com/ajeetshah/react-url-manual-modification). *solution-2* and solution-1**, there are 2 branches. – Ajeet Shah May 31 '20 at 00:49

2 Answers2

1

Your current route definition is fine:

<Switch>
    <Route exact path="/" component={Home} />
    <Route exact path="/Athletes" component={Athletes} />
    <Route
        exact
        path="/Athletes/:id/AthleteSessions"
        component={AthleteSessions}
    />
    <Route
        exact
        path="/Athletes/:athleteId/AthleteSessions/:athleteSessionId/TrainingSession"
        component={AthleteTrainingSession}
    />
</Switch>

But to go to any route you are currently doing history.push without leading /, and with a trailing / which causes the problem:

// FIRST (lets refer it first)
onClick={() => { 
    this.props.history.push({
    pathname:
        "Athletes/" + ath.AthleteId + "/AthleteSessions/",
    });
}}

// SECOND (lets refer it second)
onClick={() => {
    this.props.history.push({
    pathname:
        athSess.AthleteSessionId + "/TrainingSession/",
    });
}}

history.push('/hello') takes from localhost:3000/some/url to localhost:3000/hello --> Easy to understand

history.push('hello') takes from localhost:3000/some/url to localhost:3000/some/hello --> Not so easy, so avoid

So, everything is working fine as long as you are going to FIRST and SECOND using above history.push methods.

But problems start when you start manually typing a URL in the browser, sometimes with an ending / and sometimes without one.


Solution 1:

Change your FIRST and SECOND to use fully qualified urls with leading / and no trailing /, trailing / isn't important anymore as we using full qualified urls. Also, see Strict-Bool:

// FIRST
onClick={() => { 
    this.props.history.push({
    pathname:
        "/Athletes/" + ath.AthleteId + "/AthleteSessions",
    });
}}

// SECOND
onClick={() => {
  this.props.history.push({
    pathname: `/Athletes/${this.props.match.params?.id}/AthleteSessions/${athSess.AthleteSessionId}/TrainingSession`,
  });
}}

As we are now using full qualified URLs, it will work perfectly but the code seems hard to manage as you will be forming the full urls at each history push.


Solution 2:

SAME as Solution 1 but better code:

Define your routes using paths and makePaths:

export const paths = {
  Athletes: "/Athletes",
  AthleteSessions: "/Athletes/:id/AthleteSessions",
  AthleteTrainingSession:
    "/Athletes/:athleteId/AthleteSessions/:athleteSessionId/TrainingSession",
};

export const makePaths = {
  AthleteSessions: (id) => {
    return `/Athletes/${id}/AthleteSessions`;
  },
  AthleteTrainingSession: (athleteId, athleteSessionId) => {
    return `/Athletes/${athleteId}/AthleteSessions/${athleteSessionId}/TrainingSession`;
  },
};

// in JSX
<Switch>
  <Route exact path="/" component={Home} />
  <Route exact path={paths.Athletes} component={Athletes} />
  <Route exact path={paths.AthleteSessions} component={AthleteSessions} />
  <Route
    exact
    path={paths.AthleteTrainingSession}
    component={AthleteTrainingSession}
  />
</Switch>

And history.push:

// FIRST
onClick={() => {
  this.props.history.push({
    pathname: makePaths.AthleteSessions(ath.AthleteId),
  });
}}

// SECOND
onClick={() => {
  this.props.history.push({
    pathname: makePaths.AthleteTrainingSession(
      this.props.match.params?.id,
      athSess.AthleteSessionId
    ),
  });
}}


Solution 3:

Do nested routing. See nesting example in docs, how to do nesting? and how to access URL Params i.e. :id in path.


I would recommend going with Solution 2 but do read Solution 3 (nesting) and if / when possible go with that.
Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
0

Create a file at the root of your website called staticwebapp.config.json. The contents should be

{
  "navigationFallback": {
    "rewrite": "/index.html"
  }
}

this will solve your issue.

Steve Buck
  • 56
  • 4