问题
Hi I have been developing this application using react and react-router-dom The Page component is wrapped by a HOC that imports a contentservice to access a rest api.
My navigation is in the App component. The relevant part is the
<Link to="/page/123">About Page</Link>
and
<Link to="/page/456">Contact Page</Link>
When these links are clicked the page doesn't redraw as i expected. First time i go to 'About Page' it's all good. Then when i click to go to 'Contact Page' nothing changes. Then i click on the 'About Page' again and the 'Contact Page' shows.
In all the cases above the browser address bar shows the right path and if i refresh the page i go to the right page.
Here is my navigation page:
import React, { Component } from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import { connect } from "react-redux";
import Home from "./Home";
import Admin from "./Admin";
import Members from "./Members";
import Login from "./Login";
import Page from "./Page";
import PrivateRoute from "./PrivateRoute";
import "./App.css";
class App extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home Page</Link>
</li>
<li>
<Link to="/page/123">About Page</Link>
</li>
<li>
<Link to="/page/456">Contact Page</Link>
</li>
<li>
<Link to="/members">Members</Link>
</li>
<li>
<Link to="/admin">Admin</Link>
</li>
</ul>
</div>
<Switch>
<Route path="/login" component={Login} />
<Route path="/page/:id" component={Page} />
<Route exact path="/" component={Home} />
<PrivateRoute path="/members">
<Members />
</PrivateRoute>
<PrivateRoute path="/admin">
<Admin />
</PrivateRoute>
</Switch>
</Router>
);
}
}
const mapStateToProps = (state) => {
return {
isLoggedIn: state.isLoggedIn,
};
};
export default connect(mapStateToProps, null)(App);
This is my page component:
import React, { Component } from "react";
import WithBackend from "./WithBackend";
class Page extends Component {
constructor(props) {
super(props);
this.resource = "/pages/";
this.state = { model: null };
}
render() {
if (this.state.model != null) {
return (
<div className="container">
<div className="row">
<div className="col-md">
<h1>{this.state.model.title}</h1>
<h2 dangerouslySetInnerHTML={{ __html: this.state.model.body }} />
</div>
</div>
</div>
);
} else {
return (
<div>
<h2>Page id: {this.props.match.params.id}</h2>
</div>
);
}
}
componentDidMount() {
this.props
.getEntity(this.resource, this.props.match.params.id)
.then((model) => this.setState({ model }));
}
componentDidUpdate(nextProps) {
if (nextProps.match.params.id !== this.props.match.params.id) {
this.props
.getEntity(this.resource, nextProps.match.params.id)
.then((data) => {
this.setState({ model: data });
});
}
}
}
export default WithBackend(Page);
This is the Withbackend HOC:
import React from "react";
import ContentService from "./ContentService";
const WithBackend = (WrappedComponent) => {
class HOC extends React.Component {
constructor() {
super();
this.contentService = new ContentService();
this.getEntity = this.getEntity.bind(this);
this.getEntities = this.getEntities.bind(this);
}
getEntity(resource, id) {
return this.contentService
.getEntity(resource, id)
.then((response) => response.json())
.catch((e) => {
console.log(e);
});
}
getEntities(resource) {
return this.contentService
.getEntities(resource)
.then((response) => response.json())
.catch((e) => {
console.log(e);
});
}
render() {
return (
<WrappedComponent
getEntity={this.getEntity}
getEntities={this.getEntities}
{...this.props}
/>
);
}
}
return HOC;
};
export default WithBackend;
And the content service:
class ContentService {
baseUrl = "http://localhost:8080";
getEntity(resource, id) {
const path = this.baseUrl + resource + id;
const fetchPromise = fetch(path, {
method: "GET",
});
return Promise.resolve(fetchPromise);
}
getEntities(resource) {
const fetchPromise = fetch(this.baseUrl + resource, {
method: "GET",
});
return Promise.resolve(fetchPromise);
}
}
export default ContentService;
Has anyone got any ideas why this is happening? I am not sure if it has anything to do with the Page component being wrapped by HOC but just thought it is worth mentioning.
Thank you.
回答1:
Issue
The componentDidUpdate
lifecycle method receives the previous props
, state
, and snapshot
values, not the next ones.
componentDidUpdate
componentDidUpdate(prevProps, prevState, snapshot)
By sending the "previous" props' match param id
you were a "cycle" behind.
Solution
Use the current id
value from props.
componentDidUpdate(prevProps) {
if (prevProps.match.params.id !== this.props.match.params.id) {
this.props
.getEntity(this.resource, this.props.match.params.id)
.then((data) => {
this.setState({ model: data });
});
}
}
来源:https://stackoverflow.com/questions/65657309/react-router-path-with-id-is-not-working-correctly-for-component-wrapped-by-h