React-router urls not working when manually typing in browser

末鹿安然 提交于 2021-02-08 06:46:12

问题


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/",
  });
}}

回答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.

来源:https://stackoverflow.com/questions/62103844/react-router-urls-not-working-when-manually-typing-in-browser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!