react-routerを使用したナビゲーションリンクの作成 (STEP 3 : 他のユーザのタスクが見れるタスク管理アプリを作成する - React + Redux + Firebase チュートリアル)

★前回の記事

yucatio.hatenablog.com

Navbarを実装して、ナビゲーションリンクを作成します。 ルートパス(Home)へのリンクと、ログインしている場合は、自身のタスク一覧へのリンクを表示します。

リンクは、通常はLinkコンポーネントを使用しますが、ナビゲーションには、LinkスペシャバージョンであるNavLinkを利用します。NavLinkを使用すると、現在表示しているページのリンクだけCSSスタイルを変えたい、という要望が簡単に実現できます。

ルートパス(Home)へのリンクの追加

手始めにHomeへのリンクを追加します。activeStyleを設定して、現在のURLが/のときに文字の太さと文字色を変えています。

src/components/Navbar.js

import React from 'react'
import { NavLink } from 'react-router-dom'

let Navbar = () => (
  <div>
    <NavLink exact to='/' activeStyle={{fontWeight: "bold", color: "#DF3A01"}}>Home</NavLink>
  </div>
)

export default Navbar;

動作確認します。http://localhost:3000/users/aaaaa/todos を表示した後、Homeリンクを押します。

f:id:yucatio:20181013221633p:plain

URLが/に変化し、画面もルート(Home)に遷移して、Homeリンクの文字が赤の太字になっています。

ログイン時、自身のtodosへのリンクの追加

ログイン時に、/users/{ユーザID}/todosへのリンクを表示します。

src/components/Navbar.js

import React from 'react'
import { connect } from 'react-redux'
import { NavLink } from 'react-router-dom'
import PropTypes from 'prop-types'

let Navbar = ({uid}) => (
  <div>
    <NavLink exact to='/' activeStyle={{fontWeight: "bold", color: "#DF3A01"}}>Home</NavLink>&nbsp;
    { uid && <NavLink exact to={`/users/${uid}/todos`} activeStyle={{fontWeight: "bold", color: "#DF3A01"}}>タスクを編集する</NavLink> }
  </div>
)

Navbar.propTypes = {
  uid: PropTypes.string
}

const mapStateToProps = state => (
  { uid: state.firebase.auth.uid }
)

Navbar =connect(
  mapStateToProps
)(Navbar)

export default Navbar;

動作確認してみます。

ログアウト時はタスクへのリンクは表示されません。

f:id:yucatio:20181013222515p:plain

http://localhost:3000/ を開き、 Homeからタスク一覧へ遷移します。

f:id:yucatio:20181013224438p:plain

ルートパスから/users/{ユーザID}/todosに遷移して、todoComponentが描画されましたが、NavLinkの表示が変わりません。/users/{ユーザID}/todosに遷移したときにHomeのスタイルは解除され、タスクを編集するactiveStyleで指定したスタイルが適用されるはずですが。。

NavLinkをconnectと一緒に使用するときは、withRouterを使用する

connectを使用するとスタイルが適用されない件については、 react-router/docs/guides/blocked-updates に記載があります。URLが変更されても、connectで変更が検知されず、下位コンポーネントの再描画がされないことが原因のようです。

この現象を回避するには、connectwithRouterで囲みます。これによって、locationオブジェクトがconnectpropsとして渡されます。locationオブジェクトはページ遷移のたびに書き換えられるので、connectで変更が検知されます。これでうまく動きます。

コードを修正します。

src/components/Navbar.js

import { NavLink, withRouter } from 'react-router-dom' // 変更

// 中略

Navbar = withRouter(connect(
  mapStateToProps
)(Navbar))

// 後略

動作確認をします。再び http://localhost:3000/ を開き、 Homeからタスク一覧へ遷移します。

f:id:yucatio:20181013230103p:plain

Home画面から/users/{ユーザID}/todosに遷移したときに、NavLinkのスタイル切り替えも行われました。

以上でナビゲーションリンクが完成しました。

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com