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

时间:2018-02-22 23:35:10

标签: reactjs react-router back-button browser-history gatsby

我有一个文章组件,显示帖子列表。该列表是分页的,因此每页最多可显示10个帖子。有一个"下一页"单击时按钮将更新组件状态和相应的url参数,如下所示:

第1页:/ news

第2页:/ news?page = 2

第3页:/ news?page = 3

......等等。设置constructor()render()方法的方式是,如果用户直接导航到/ news?page = 3,它将读取此URL参数并显示正确的帖子。

我遇到的问题是浏览器后退和前进按钮似乎不会重新呈现页面。因此,如果用户点击"下一页"按钮几次,然后点击后退按钮,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 个答案:

答案 0 :(得分:7)

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

你所谓的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;

答案 1 :(得分:2)

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

另一种方法是使用React-Router-DOM,它是ReactJS应用程序中路由的最新路由模块。因此,要参考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> 
  

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