この記事は公開されてから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
を渡しています。
src/Home.tsx
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
を、ルーティングではなく、通常のタグコンポーネントとして使用しています。
MyProfile.tsx
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にアクセスするようにしていますが、この場合は正常に動きません。
src/header/Header.tsx(エラー)
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にアクセスできるようになります。
src/header/Header.tsx
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
以上