React Router - 带有 :id 的路径对于 HOC 包装的组件无法正常工作

IT技术 reactjs react-router
2021-05-19 06:40:50

嗨,我一直在使用 react 和 react-router-dom 开发此应用程序 Page 组件由 HOC 包装,该 HOC 导入 contentservice 以访问 rest api。

我的导航位于 App 组件中。相关部分是

<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 包装的 Page 组件有什么关系,但只是认为值得一提。

谢谢你。

1个回答

问题

componentDidUpdate生命周期方法接收以前 propsstatesnapshot值,而不是未来的。

组件已更新

componentDidUpdate(prevProps, prevState, snapshot)

通过发送“上一个”props的匹配参数,id您落后了一个“循环”。

解决方案

使用idprops 中的当前值。

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 });
      });
  }
}