2

I'm very new to React and first time time trying to implement navigation to a new page by pushing it to the history but am stuck on this error Cannot read property 'push' of undefined for react use history for a couple of hours now and think I need some help or guidance please.

Here are my small mvp components (I'm using Hooks):

import React, {useEffect, useState} from 'react';
import {BrowserRouter as Router, Route, Switch, useHistory} from "react-router-dom";
import Report from "./components/Report";

function App() {

let history = useHistory();

function handleClick() {
    history.push("/report");
}

return (
    <Router>
        <Route path="/report" component={Report}/>
        <div>
            <button onClick={handleClick}>Click me</button>
        </div>

    </Router>
);
}

export default App

And

import React from "react";
import {withRouter} from "react-router-dom";

const Report = () => {

return (
    <div>Hello from report</div>
);

}

export default withRouter(Report)

Thank you very much.

Update

codesandbox.io/s/crazy-hill-1i6gb
I've added my complete code on the above link. The url now changes and no longer get the undefined error as per @Abir answer but the click me button still shows up rather than the text for the Report component.

Francislainy Campos
  • 3,462
  • 4
  • 33
  • 81
  • Does this answer your question? [Uncaught TypeError: Cannot read property 'push' of undefined (React-Router-Dom)](https://stackoverflow.com/questions/44009618/uncaught-typeerror-cannot-read-property-push-of-undefined-react-router-dom) – izik Sep 06 '20 at 07:52
  • Hi, thank you for the quick reply. I've actually gone through quite a few questions and answers at this moment and this one too. It seems to be asking me to use withRouter on the component I'm trying to navigate to but I have that so not sure what else I could be missing. – Francislainy Campos Sep 06 '20 at 07:54
  • Can you share the codesandbox link? It will be easier to debug and understand root problem. – sidverma Sep 06 '20 at 07:56
  • Hi, these two classes are everything I have. – Francislainy Campos Sep 06 '20 at 07:57
  • 1
    The problem here is to use hook `useHistory` outside of the ``, to fix this you just simply move them all in a component of a `` – tmhao2005 Sep 06 '20 at 07:58

2 Answers2

13

The issue is because your Router component is nested inside of your App component rather than your App being nested inside of your router. The router acts as sort of a context provider and without your app being nested in the router the useHistory() hook has no provider to get the History from.

You can try something like this:

import React, {useEffect, useState} from 'react';
import {BrowserRouter as Router, Route, Switch, useHistory} from "react-router-dom";
import Report from "./components/Report";

function Content(){
    let history = useHistory();
    

    function handleClick() {
        history.push("/report");
    }
    
    return (
        <div>
            <button onClick={handleClick}>Click me</button>
        </div>
    )

}

function App() {

    return (
        <Router>
            <Route path="/report" component={Report}/>
            <Content />
        </Router>
    );
}

export default App

Abir Taheer
  • 2,502
  • 3
  • 12
  • 34
1

As per the comments under the accepted answer here is the full gist of what worked to solve the issue.

import React from "react";
import { BrowserRouter as Router, Route, useHistory } from "react-router-dom";
import Report from "./components/Report";

function Content() {
let history = useHistory();

function handleClick() {
 history.push("/report");
}

return (
 <div>
    <button onClick={handleClick}>Click me</button>
 </div>
 );
}

function App() {
return (
 <Router>
   <Route path="/report" exact component={Report} />
   <Route path="/" exact component={Content} />
 </Router>
);
}

export default App;

And

import React from "react";

const Report = () => {
return <div>Hello from report</div>;
};

export default Report;
Francislainy Campos
  • 3,462
  • 4
  • 33
  • 81
  • One thing I'd like to add is that you don't need to wrap your Report component export using `withRouter`. The reason being that you're not doing anything inside of the Report component that requires receiving the router as a property. – Abir Taheer Sep 06 '20 at 09:30
  • Cool, thank you for highlighting that. – Francislainy Campos Sep 06 '20 at 11:12