[React Router] 直接ルーティングしていない孫コンポーネントからhistoryにアクセス可能にする(WithRouter)
こんにちは、CX事業本部 IoT事業部の若槻です。
今回は、React Router(react-router-dom)でWithRouter
を使って、直接ルーティングしていない孫コンポーネントからhistoryにアクセス可能にしてみました。
やってみた
具体的にやりたいこととしてはこんな感じです。ルーティング先の子コンポーネント内で通常のタグコンポーネントとして使用されている孫コンポーネント内でhistoryにアクセスできるようにしてみます。
<親コンポーネント> ↓ ルーティング ←ここでprops.history.pushで値(state.userName)を渡す <子コンポーネント> ↓ 通常のタグコンポーネントとして使用 <孫コンポーネント> ←ここでstate.userNameにアクセスする
実装
次のようなコンポーネント構成で確認してみます。
- 親コンポーネント:
Home
- 子コンポーネント:
MyProfile
- 孫コンポーネント:
Header
親コンポーネントHome
では、props.history.push
で子コンポーネントMyProfile
へのルーティングを行っています。その際にstate.userName
を渡しています。
import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; const Home = (props: RouteComponentProps) => { return ( <div> <h1>Home page</h1> <ul> <li> <button onClick={() => { props.history.push({ pathname: '/profile', state: { userName: 'わかつき' } }); }} > Go to my profile </button> </li> </ul> </div> ); }; export default Home;
MyProfile
では、孫コンポーネントHeader
を、ルーティングではなく、通常のタグコンポーネントとして使用しています。
import React from 'react'; import Header from './header/Header'; import { RouteComponentProps } from 'react-router-dom'; const MyProfile: React.FC<RouteComponentProps> = ( props ) => { return ( <div> <Header /> <h1>This is my profile</h1> <ul> {props.location.state && ( <li> <button onClick={() => { props.history.goBack(); }} > Back </button> </li> )} </ul> </div> ); }; export default MyProfile;
孫コンポーネントHeader
です。props.location.state.userName
によりhistoryにアクセスするようにしていますが、この場合は正常に動きません。
import React from 'react'; import './Header.css'; import { RouteComponentProps } from 'react-router-dom'; type Props = RouteComponentProps< {}, {}, { userName: string } >; const Header: React.FC<Props> = (props) => { return ( <div className="header"> <h1>ヘッダー</h1> {props.location.state && props.location.state.userName} </div> ); }; export default Header;
props.location.state.userName
へのアクセスがundefined
となりエラーとなってしまいます。
MyProfile
側でもHeader
の読み込みがエラーとなってしまいます。
そこでWithRouterを使用することにより、直接props.history.push
によるルーティングをしていないコンポーネントでもhistoryにアクセスできるようになります。
import React from 'react'; import './Header.css'; import { RouteComponentProps, withRouter } from 'react-router-dom'; type Props = RouteComponentProps< {}, {}, { userName: string } >; const Header: React.FC<Props> = (props) => { return ( <div className="header"> <h1>ヘッダー</h1> {props.location.state && props.location.state.userName} </div> ); }; export default withRouter(Header);
デモ
Home Page/
でボタンをクリックすると、親コンポーネントHome
からのルーティング時にhistoryにより渡したuserName
に、孫コンポーネントHeader
からアクセスできています。
子コンポーネントMyProfile
のページ/prifile
に直接アクセスすると、ルーティングは行われていないので、Header
コンポーネントからuserName
にはアクセスできず、表示はされません。
参考
- reactjs - What is withRouter for in react-router-dom? - Stack Overflow
- react-router-domのwithRouter apiを使う場面 - code-log
- React RouterのpropsをTypeScriptで型付けする | DevelopersIO
以上