LoginSignup
14
8

More than 1 year has passed since last update.

【React】React Router v6でのuseNavigateでのStateの渡し方

Last updated at Posted at 2022-02-07

初めに

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 のメッセージをフラッシュメッセージとして表示する

src/RootButton.tsx
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>
    )
}

src/FlashMessage.tsx
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 に書き換えます。

src/RootButton.tsx
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>
    )
}


src/FlashMessage.tsx
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 が分割して書くことができるようになったのは便利になりました。

参考

公式アップグレードガイド

14
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
8