Реагирующий маршрутизатор — путь с: id работает некорректно для компонента, обернутого HOC

#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

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) мне здесь со ссылкой на сообщение, и я смогу взглянуть, когда это будет доступно.