Gatsby.js:使用 URL 参数和浏览器后退/前进按钮导航
Gatsby.js: Navigating with URL Parameters and the Browser Back / Forward Buttons
我有一个显示文章列表的文章组件。该列表已分页,因此每页最多可以显示 10 个帖子。有一个 "Next Page" 按钮,单击它会更新组件状态和相应的 url 参数,如下所示:
第 1 页:/新闻
第 2 页:/news?page=2
第 3 页:/news?page=3
...等等。 constructor()
和 render()
方法的设置方式,例如,如果用户直接导航到 /news?page=3,它将读取此 URL 参数并显示正确的帖子。
我遇到的问题是浏览器的后退和前进按钮似乎没有重新呈现页面。因此,如果用户点击 "Next Page" 按钮几次,然后点击后退按钮,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>
);
}
}
您的页面不会重新呈现,因为它实际上是同一页面 - 该组件已安装。当您在 constructor()
中获取数据时,您的页面不会更新,因为 React 组件的构造函数在安装之前被调用 (source)。
你所说的urlParam
只是componentWillReceiveProps(nextProps)
应该在nextProps.location.search
收到的新道具。
编辑:
您必须提升状态,因为只有根组件会收到浏览器后退和前进按钮上的 props.location
。 Articles 组件 nerver 的 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 应用程序中用于路由的最新路由模块。因此,对于 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>
keep in mind that router should contain only single child other wise, it won't work as expected. This way routing becomes very easy to work with.
我有一个显示文章列表的文章组件。该列表已分页,因此每页最多可以显示 10 个帖子。有一个 "Next Page" 按钮,单击它会更新组件状态和相应的 url 参数,如下所示:
第 1 页:/新闻
第 2 页:/news?page=2
第 3 页:/news?page=3
...等等。 constructor()
和 render()
方法的设置方式,例如,如果用户直接导航到 /news?page=3,它将读取此 URL 参数并显示正确的帖子。
我遇到的问题是浏览器的后退和前进按钮似乎没有重新呈现页面。因此,如果用户点击 "Next Page" 按钮几次,然后点击后退按钮,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>
);
}
}
您的页面不会重新呈现,因为它实际上是同一页面 - 该组件已安装。当您在 constructor()
中获取数据时,您的页面不会更新,因为 React 组件的构造函数在安装之前被调用 (source)。
你所说的urlParam
只是componentWillReceiveProps(nextProps)
应该在nextProps.location.search
收到的新道具。
编辑:
您必须提升状态,因为只有根组件会收到浏览器后退和前进按钮上的 props.location
。 Articles 组件 nerver 的 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 应用程序中用于路由的最新路由模块。因此,对于 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>
keep in mind that router should contain only single child other wise, it won't work as expected. This way routing becomes very easy to work with.