ReactRouter~子コンポーネントでthis.porps.history.push()がTypeError: Cannot read property 'push' of undefinedになる
そこそこハマったけど意外と情報が出てこなかったので記録
react等のバージョンは以下(package.json)
{ "react": "^16.13.1", "react-dom": "^16.13.1", "react-router-dom": "^5.2.0", "react-scripts": "3.4.3" }
今回発生したパターンの発生条件としては子コンポーネントにpropsを渡すためにcomponentではなくrenderを使ったことで、解決策としては子コンポーネントのexport時にwithRouterを使うことでした
以下の手順でサンプルの環境を作りました
npm create-react-app trial-router cd trial-router npm install react-router-dom
src/App.jsを以下の内容に更新
import React from 'react'; import { BrowserRouter, Route } from 'react-router-dom'; import Base from './BaseComponent'; import Moved from './MovedComponent'; function App() { return ( <div className="App"> <h1>HOME</h1> <BrowserRouter> <Route exact path="/" render={() => <Base text={"Base"} /> } /> <Route path="/moved" render={() => <Moved text={"Moved"} /> } /> </BrowserRouter> </div> ); } export default App;
src/ChildComponent.jsを以下の内容で作成
import React from 'react'; class Base extends React.Component { move = () => { this.props.history.push("/moved"); } render() { return ( <> <div>{this.props.text}</div> <button onClick={this.move}> Move </button> </> ); } } export default Base);
src/MovedComponent.jsを以下の内容で作成
import React from 'react'; class Moved extends React.Component { move = () => { this.props.history.push("/"); } render() { return ( <> <div>{this.props.text}</div> <button onClick={this.move}> Back </button> </> ); }; } export default Moved;
ファイルを作成して
npm start
すると以下のようなページができるはず
このページでMoveボタンを押すと
みごと「TypeError: Cannot read property 'push' of undefined」が発生する
解決策としてはChildComponent.jsとMovedComponent.jsをそれぞれ以下のように変更する
v
// ChildComponent.js import React from 'react'; // withRouterをimport import { withRouter } from 'react-router-dom'; class Base extends React.Component { move = () => { this.props.history.push("/moved"); } render() { return ( <> <div>{this.props.text}</div> <button onClick={this.move}> Move </button> </> ); } } // withRouterの引数にBaseを指定 export default withRouter(Base)
// MovedComponent.js import React from 'react'; // withRouterをimport import { withRouter } from 'react-router-dom'; class Moved extends React.Component { move = () => { this.props.history.push("/"); } render() { return ( <> <div>{this.props.text}</div> <button onClick={this.move}> Back </button> </> ); }; } // withRouterの引数にMovedを指定 export default withRouter(Moved);
2ファイルとも修正は同じ
withRouterを追加したらボタンを押すことでChildとMovedを行き来できるはず
ちなみにクラス構文を使わずにReact Hooksを使っても同様のエラーが発生した。