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

Posted

技术标签:

【中文标题】Gatsby.js:使用 URL 参数和浏览器后退/前进按钮导航【英文标题】:Gatsby.js: Navigating with URL Parameters and the Browser Back / Forward Buttons 【发布时间】:2018-08-02 23:39:30 【问题描述】:

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

第 1 页:/新闻

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

【问题讨论】:

你能检查componentWillReceiveProps是否在后退/前进按钮点击时被触发? hm 它根本没有被触发,在后退/前进点击或初始组件加载时 您使用的是哪个版本的 gatsby?通过浏览器按钮导航时,您是否还看到任何控制台错误? @DivyanshuMaithani 我使用的是 gatsby 版本 1.9.158,没有出现控制台错误 【参考方案1】:

您的页面不会重新呈现,因为它实际上是同一页面 - 组件已安装。当您在 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;

【讨论】:

感谢@Nenu 的回复,但在初始页面加载或使用“下一页”按钮导航时,似乎从未调用过componentWillReceiveProps 生命周期方法 这很奇怪。我发现here 有时 componentWillReceiveProps 不会因为不明原因而触发……我鼓励您在 gatsby 项目中创建一个新页面,看看 componentWillReceiveProps 是否有效(这是我在回答这个代码示例之前所做的)。然后尝试调试这个或重构你的代码结构。 我有同样的直觉,听起来很奇怪,当你的路线改变时它不会触发 在我的 gatsby 项目中,一个页面导入并显示了这个组件。我的猜测是,因为它实际上并没有链接到新页面,而是更新了内部组件的状态并随后更新了 URL,这导致后退/前进按钮没有任何效果。有没有办法让它加载整个页面,就好像它是从另一个页面导航一样? @Nenu 原来除了提升状态,我还需要更新 gatsby / gatsby-link!我分别使用的是 1.9.158 和 1.6.34 版本,更新到 1.9.231 和 1.6.39 后它开始工作。感谢所有的帮助!【参考方案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> 

请记住,路由器应该只包含一个孩子,否则它将无法按预期工作。这样路由就变得很容易使用了。

【讨论】:

感谢@Amit 的回复,但我认为 react 路由器解决方案不适用于这种特殊情况。您能否使用历史对象演示解决方案?

以上是关于Gatsby.js:使用 URL 参数和浏览器后退/前进按钮导航的主要内容,如果未能解决你的问题,请参考以下文章

js 监控用户点击浏览器“后退”按钮(并禁用),能实用IE和360两种浏览器

gatsby.js - 高级入门 - 实现 2 个 url 前缀(站点的 2 个不同部分)?

PHP GET 和 POST 的区别面试

PHP GET 和 POST 的区别面试

GraphQL - Gatsby.js- React 组件。 - 如何查询变量/参数?

使用 gatsby 以编程方式导航到动态 url