どうも、イソップです。
昨日紹介したreact-tabsですが、タブ切り替えと同時にURLも変更したいことがあると思います。
【昨日の記事】【React】react-tabsが一番シンプルで使いやすい
今日は、react-tabsを使ったルーティング設定について紹介します。
ルーティング設定を追加
今回の目標は、/page
で表示されるページ内にタブ切り替えがあり、
そのタブを切り替えると、/page
、/page/tab2
、/page/tab3
とURLが変更されます。
ではまずはルーティングを追加します。
<Route path="/" component={App}>
<Route path="page" component={Page}>
<Route path=":tab" />
</Route>
</Route>
react-routerの v3.x
を例にしています。
<Route path=":tab" />
がタブ用のURL設定です。
次に、昨日の記事で紹介した react-tabs
のコンポーネントを Page
コンポーネントに配置します。
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
class Page extends Component {
handleSelect(index, last) {
console.log('Selected tab: ' + index + ', Last tab: ' + last);
}
render() {
return (
<Tabs
onSelect={this.handleSelect}
selectedIndex={2}
>
<TabList>
<Tab>tab1</Tab>
<Tab>tab2</Tab>
<Tab>tab3</Tab>
</TabList>
<TabPanel>
<h2>Hello from tab1</h2>
</TabPanel>
<TabPanel>
<h2>Hello from tab2</h2>
</TabPanel>
<TabPanel>
<h2>Hello from tab3</h2>
</TabPanel>
</Tabs>
);
}
}
この Page
コンポーネントを編集していきます。
タブの初期化と切り替え時の処理
タブを切り替えた際のURLリストを保持しておく必要があります。
今回は Page
コンポーネントに持たせます。
class Page extends Component {
constructor(props) {
super(props);
this.tabs = [ '', 'tab2', 'tab3' ];
}
...
}
constructor
の中で、this.tabs
を定義します。
先ほどrouteで定義した path=":tab"
が、コンポーネントの props.params.tab
で取得できます。
例えば、URLが /page/tab2
でアクセスすると、props.params.tab
には tab2
がセットされます。
このパスキーワードと、this.tabs
で定義したキーワードがマッチしたら、選択したタブに対応するパネルを表示します。
マッチしなかったら、例外処理用のビューコンポーネントを表示しておくと良いでしょう。
では初期化とタブ選択時の処理を追加します。
class Page extends Component {
constructor(props) {
super(props);
this.tabs = [ '', 'tab2', 'tab3' ];
this.handleSelect = this.handleSelect.bind(this); // メソッド内のthisをPageに
}
// indexを取得するメソッドを定義
getTabIndex(tab = this.props.params.tab || '') {
return this.tabs.indexOf(tab);
}
// タブ選択時のコールバック
handleSelect(index, last) {
// indexは最後の "/" を付けない
const tabPath = this.tabs[index] ? '/' + this.tabs[index] : '';
// URLを変更する
this.props.router.push('/page' + tabPath);
}
render() {
// this.tabsに一致しない場合はNoTabを表示する
if (this.getTabIndex() < 0) return <NoTab />;
return (
<Tabs
onSelect={this.handleSelect}
selectedIndex={this.getCategoryIndex()}
>
...
);
}
}
上から順番に、説明していきます。
初期化処理の解説
// indexを取得するメソッドを定義
getTabIndex(tab = this.props.params.tab || '') {
return this.tabs.indexOf(tab);
}
getTabIndex
メソッドは、URLの :tab
キーワードから、this.tabs
にマッチするインデックス(順番)を取得します。
これは、タブの初期表示インデックスに利用します。
<Tabs
onSelect={this.handleSelect}
selectedIndex={this.getCategoryIndex()}
>
キーワードにマッチしなければ、-1
が返ります。つまり、表示するタブがないことになります。
render() {
// this.tabsに一致しない場合はNoTabを表示する
if (this.getTabIndex() < 0) return <NoTab />;
...
例では、<NoTab />
コンポーネントを表示しています。中身に「ページは存在しません」としておくと良いです。
タブ選択処理の解説
// タブ選択時のコールバック
handleSelect(index, last) {
// indexは最後の "/" を付けない
const tabPath = this.tabs[index] ? '/' + this.tabs[index] : '';
// URLを変更する
this.props.router.push('/page' + tabPath);
}
そして、タブ選択時の handleSelect
メソッドでは、選択したタブのURLを整形し、
react-routerの機能でURLを変更します。
初期表示URLは、/page
にしたいので、キーワードが何もなければそのままに、キーワードがあれば頭に /
を付けています。
これで実装完了です。