初めに
react router をバージョンアップをした際に、useHistory が廃止され useNavigate が追加されました。
useHistory で使っていたが useNavigate での使い方がいまいちわかりずらかったので記事にします。
やりたいこと
useHistory の state を useNavigate で使う
環境
React 17.0.2
React router 6.2.1
typescript 4.2.3
本文
フックを利用すると、遷移先に state を渡すことができます。
v5 の時
useHistory を使って、フラッシュメッセージ機能を実装しています。
ボタンを押すとルートに遷移し、state のメッセージをフラッシュメッセージとして表示する
import { FC } from 'react'
import { useHistory } from 'react-router-dom'
const RootButton:FC = ()=> {
const hisotry = useHistory()
const toRoot = () => {
hisotry.push('/',{message: '成功',type: 'success'}) //第一引数に遷移するパス、第二変数にstateを渡す
}
return (
<button type="button" onClick={toRoot}>
Root
</button>
)
}
import { FC,useState } from 'react';
import { Message } from 'semantic-ui-react';
import { useLocation } from 'react-router-dom'
const FlashMessage:FC = ()=>{
const location = useLocation(); //location.stateでhistory.pushの引数で渡したstateを取り出すことができる
const [state,setState] = useState(false);
const dismiss = ()=> setState((prevState)=> prevState && false)
return (
<>
{state &&
(location.state.type === 'success' ? (
<Message success onDismiss={dismiss}>
<Message.Header
content={location.state.message}
/>
</Message>
) : (
<Message error onDismiss={dismiss}>
<Message.Header
content={message}
/>
</Message>
))}
</>
);
}
これでボタンを押したら、ルートに遷移しフラッシュメッセージが表示されます。
v6 の時
バージョンが 6 になると、useHistory を useNavigate に書き換える必要があります。
history.push を navigate に書き換えます。
import { FC } from 'react'
import { useNavigate } from 'react-router-dom'
const RootButton:FC = ()=> {
const navigate = useNavigate()
const toRoot = () => {
navigate('/',{state: {message: '成功',type: 'success' }})
//第一引数に遷移するパス、第二変数にstateをオブジェクトで渡す
}
return (
<button type="button" onClick={toRoot}>
Root
</button>
)
}
import { FC,useState } from 'react';
import { Message } from 'semantic-ui-react';
import { useLocation } from 'react-router-dom';
const FlashMessage:FC = ()=>{
const location = useLocation(); //location.stateでstateを取り出すことができる 型が変わっているので注意
const [state,setState] = useState(false);
const dismiss = ()=> setState((prevState)=> prevState && false);
type MessageState = {message: string, type: 'success' | 'error';
const messagestate = location.state as MessageState; //型を無理やり与える
return (
<>
{state &&
(messagestate.type === 'success' ? (
<Message success onDismiss={dismiss}>
<Message.Header
content={messagestate.message}
/>
</Message>
) : (
<Message error onDismiss={dismiss}>
<Message.Header
content={messagestate.message}
/>
</Message>
))}
</>
);
}
バージョンが上がって state がオプションの一部に変更されたので、第二引数のオブジェクトの中で渡す必要があります。
まとめ
v6 にバージョンを上げるのは簡単ですが、Switch を書き換えたりと面倒なことが多いですが Router が分割して書くことができるようになったのは便利になりました。