投稿のリストを表示するArticlesコンポーネントがあります。リストはページ分けされているため、1ページあたり最大10件の投稿を表示できます。 「次のページ」ボタンがあり、クリックするとコンポーネントの状態と対応するurlパラメータが次のように更新されます。
ページ1:/ news
ページ2:/ news?page = 2
ページ3:/ news?page = 3
...等々。 constructor()
メソッドとrender()
メソッドの設定方法では、このURLパラメータを読み取り、たとえばユーザーが/ news?page = 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>
);
}
}
実際には同じページであるため、ページは再レンダリングされません-コンポーネントはすでにマウントされています。 constructor()
でデータをフェッチしているとき、Reactコンポーネントのコンストラクターがマウントされる前に呼び出されるため、ページは更新されません( source )。
urlParam
は、componentWillReceiveProps(nextProps)
がnextProps.location.search
で受け取る必要がある新しい小道具です。
ルートコンポーネントのみがブラウザの[戻る]ボタンと[進む]ボタンでprops.location
を受け取るため、状態を上げる必要があります。 Articlesコンポーネントの神経機能のpathname
プロップが変更されたため、componentWillReceiveProps
はここで起動しません。
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>
);
}
}
import React from 'react';
const Articles = ({ nextPage, currentPage }) => {
return (
<div>
<div>Page: {currentPage}</div>
<button onClick={() => nextPage()}>Next Page</button>
</div>
);
};
export default Articles;
これは、ウィンドウオブジェクト内に存在する履歴オブジェクトを使用して解決できます。
別の方法は、ReactJSアプリケーションでルーティングするための最新のルーティングモジュールであるReact-Router-DOMを使用することです。したがって、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>
それ以外の場合、ルーターには子を1つだけ含める必要があることに注意してください。期待どおりに機能しません。このようにして、ルーティングは非常に扱いやすくなります。