![[React Router] 直接ルーティングしていない孫コンポーネントからhistoryにアクセス可能にする(WithRouter)](https://devio2023-media.developers.io/wp-content/uploads/2019/01/react.jpg)
[React Router] 直接ルーティングしていない孫コンポーネントからhistoryにアクセス可能にする(WithRouter)
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、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
以上







