Gatsby.js:使用 URL 参数和浏览器后退/前进按钮导航

IT技术 reactjs react-router back-button browser-history gatsby
2021-04-30 16:26:48

我有一个文章组件,它显示了一个帖子列表。该列表是分页的,因此每页最多可以显示 10 个帖子。有一个“下一页”按钮,点击后会更新组件状态和相应的 url 参数,如下所示:

第 1 页:/新闻

第 2 页:/news?page=2

第 3 页:/news?page=3

...等等。的方式constructor()render()方法的建立,它会读取这个URL参数,并显示正确的岗位如果用户导航直接/新闻?页= 3,例如。

我遇到的问题是浏览器的后退和前进按钮似乎没有重新呈现页面。因此,如果用户点击“下一页”按钮几次,然后点击后退按钮,URL 将更新,但页面不会重新呈现。有没有办法强迫它这样做?

我猜有一种方法可以通过添加 window.history 侦听器来完成此操作,但我不确定是否有推荐的做法与gatsby-link.

这是组件的精简版本以供参考:

import React, { Component } from 'react';
import { navigateTo } from 'gatsby-link';
import getUrlParameter from '../functions/getUrlParameter';

export default class extends Component {
  constructor(props) {
    super(props);

    /* external function, will grab value
    * of ?page= url parameter if it exists */
    const urlParamPage = getUrlParameter('page');
    const currentPage = urlParamPage ? urlParamPage : 1;

    this.state = {
      currentPage
    };
  }

  nextPage() {
    const { props, state } = this;

    const urlParam = state.currentPage > 1
      ? `?page=${state.currentPage}`
      : '';

    navigateTo(props.pathname + urlParam);
    this.setState({currentPage: this.state.currentPage + 1});
  }

  render() {
    const { props, state } = this;

    const articles = props.articles
      .slice(state.currentPage * 10, state.currentPage * 10 + 10);

    return (
      <div>
        <ul>
          {articles.map((article) => <li>{article.title}</li>)}
        </ul>

        <button onClick={() => this.nextPage()}>Next Page</button>
      </div>
    );
  }
}
2个回答

您的页面不会重新呈现,因为它实际上是同一页面 -组件已经安装当您在 中获取数据时constructor(),您的页面不会更新,因为 React 组件的构造函数在安装之前被调用()。

你所说urlParam的只是一个componentWillReceiveProps(nextProps)应该在nextProps.location.search.

编辑:

您必须提升状态,因为只有根组件会收到props.location浏览器的后退和前进按钮。pathname你的文章组件神经支柱发生了变化,这就是为什么componentWillReceiveProps从不在这里触发。

代码:

/src/pages/root.js

import React, { Component } from 'react';
import { navigateTo } from 'gatsby-link';

import Articles from '../components/Articles';

export default class Test extends Component {
  constructor(props) {
    super(props);

    this.state = {
      currentPage: 1,
      data: {}, // your ext data
    };

    this.nextPage = this.nextPage.bind(this);
  }

  nextPage() {
    const { currentPage } = this.state;
    const { pathname } = this.props.location;
    const url = `${pathname}?page=${currentPage + 1}`;

    this.setState({ currentPage: currentPage + 1 });
    navigateTo(url);
  }

  componentWillReceiveProps(nextProps) {
    const { pathname, search } = nextProps.location;
    const getParam = /(\d+)(?!.*\d)/;

    const currentPage = search !== '' ? Number(search.match(getParam)[0]) : 1;

    /* get your ext. data here */
    const data = {};

    this.setState({ currentPage, data });
  }

  render() {
    const { currentPage, data } = this.state;
    return (
      <div>
        {/* other contents here */}
        <Articles
          nextPage={this.nextPage}
          currentPage={currentPage}
          data={data}
        />
      </div>
    );
  }
}

/src/components/Articles.js

import React from 'react';

const Articles = ({ nextPage, currentPage }) => {
  return (
    <div>
      <div>Page: {currentPage}</div>
      <button onClick={() => nextPage()}>Next Page</button>
    </div>
  );
};

export default Articles;

这可以使用 window 对象中存在的历史对象来解决。

另一种方法是使用 React-Router-DOM,它是 ReactJS 应用程序中用于路由的最新路由module。所以要参考 V4 路由器,请遵循此代码。

  import {BrowserRouter as Router, Route, Switch, Redirect} from 'react-router-dom';

导入路由器后,只需尝试将根组件的范围限定在其中,然后您就可以在其中创建路由。

  <Router>
    <div className="App" id="App">
      <Route path="/" exact component={Home}/>
      <Route path="/about" exact component={About}/>  
      <Route path="/misreports" exact component={MISReport}/>  
      <Route path="/contact" exact component={Contact}/>  
    </div>
  </Router> 

请记住,路由器应该只包含一个孩子,否则它不会按预期工作。这种方式路由变得非常容易使用。