#reactjs #react-router
#reactjs #реагирующий маршрутизатор
Вопрос:
Привет, я разрабатывал это приложение, используя react и react-router-dom. Компонент страницы обернут HOC, который импортирует contentservice для доступа к rest api.
Моя навигация находится в компоненте приложения. Соответствующей частью является
<Link to="/page/123">About Page</Link>
и
<Link to="/page/456">Contact Page</Link>
При нажатии на эти ссылки страница перерисовывается не так, как я ожидал. В первый раз, когда я захожу на страницу «О странице», все хорошо. Затем, когда я нажимаю, чтобы перейти на «Страницу контактов», ничего не меняется. Затем я снова нажимаю на «Страницу о программе», и появляется «Страница контактов».
Во всех приведенных выше случаях адресная строка браузера показывает правильный путь, и если я обновляю страницу, я перехожу на нужную страницу.
Вот моя страница навигации:
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);
Это компонент моей страницы:
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);
Это 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;
И контент-сервис:
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;
У кого-нибудь есть идеи, почему это происходит? Я не уверен, имеет ли это какое-либо отношение к компоненту страницы, обернутому HOC, но просто подумал, что это стоит упомянуть.
Спасибо.
Комментарии:
1.
componentDidUpdate
получает предыдущий реквизит и состояние, а не следующий реквизит. Возможно, вам потребуется отправить текущееid
значение, т.е.getEntity(this.resource, this.props.match.params.id)
.
Ответ №1:
Проблема
Метод componentDidUpdate
жизненного цикла получает предыдущие props
state
snapshot
значения, , и , а не следующие.
componentDidUpdate(prevProps, prevState, snapshot)
Отправив параметр соответствия реквизита «предыдущему» реквизиту id
, вы отстали на «цикл».
Решение
Используйте текущее id
значение из реквизита.
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 });
});
}
}
Комментарии:
1. @Allema_s У вас есть новая проблема / вопрос, о котором вы хотите спросить? Если используемый вами компонент может использовать перехватчики React, то ему не нужен какой
withRouter
-либо компонент более высокого порядка, он может использоватьuseParams
перехватчик напрямую. Если вы решите задать новый вопрос на SO, не стесняйтесь, напишите (@ me) мне здесь со ссылкой на сообщение, и я смогу взглянуть, когда это будет доступно.