问题
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 fromlocalhost:3000/some/url
tolocalhost:3000/hello
--> Easy to understand
history.push('hello')
takes fromlocalhost:3000/some/url
tolocalhost: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