history.push() and props.location.state cause "Cannot read property 'state' of undefined"
Solution 1
On PageEdit.js ,
you should access the state by using useLocation()
import {useLocation} from 'react-router-dom'
const location = useLocation()
console.log(location.state)
you will be able to access your data
Solution 2
According to the route
documentation you are not using it correctly.
It should either be :
<Route exact path="/" component={PageList}> />
or
<Route exact path="/" render={props => <PageList {...props}> />
This way, you'll correctly have the props
coming from react-router
Solution 3
url parameters
You should define your URL to accept an id url parameter.
<Route path="/edit/:id" component={PageEdit} />
So this way you can redirect to the proper location and even copy past URLs to share with the page id in it.
In <pageEdit />
component, you can access id using let { id } = useParams();
then load it from your list of pages.
Shared state between components
A more complex solution could be to adopt a shared state between all your component , which is what redux is design for.
Related videos on Youtube
AxSch
Updated on June 04, 2022Comments
-
AxSch almost 2 years
Problem description
I am using react-router-dom together with react functional components. I am trying to pass data with "history.push", which is not working.
The redirection to another page with "history.push" itself is working great. BUT the problem is: passing data via "state: {...}" to a component causes: "Cannot read property 'state' of undefined" when I try to access it with "props.location.state" within the component.
I have tried different variations of defining the route.
Code
app.js
import React from 'react'; import PageList from './pages/PageList'; import PageEdit from './pages/PageEdit'; import { BrowserRouter as Router, Route, Switch} from "react-router-dom"; export default function App() { return ( <Router> <Switch> <Route exact path="/"> <PageList /> </Route> <Route path="/edit"> <PageEdit/> </Route> </Switch> </Router> ); }
PageList.js
import React from 'react'; import { useHistory } from "react-router-dom"; import Button from '@material-ui/core/Button'; export default function PageList() { let history = useHistory(); function handleTestClick(e) { history.push({ pathname: "/edit", state: {id: 123} }); } return ( <div> <Button onClick={handleTestClick}>Test</Button> </div> ); }
PageEdit.js
import React, { useEffect } from 'react'; export default function PageEdit(props) { const test = props.location.state; console.log("Meine ID:" + test.id); return ( <div> <h1>Edit Page</h1> </div> ); }
What I tried:
- to use useEffect() to avoid any issues with reloading the page:
useEffect(() => { const test = props.location.state; console.log("Meine ID:" + test.id); }, []);
- other types of definitions for the route
<Route exact path="/" component={PageList}> </Route> <Route path="/edit" component={PageEdit}> </Route>
- add a location prop:
<Route exact path="/" component={PageList} location={props.location}> </Route> <Route path="/edit" component={PageEdit} location={props.location}> </Route>
- Pass props to component (even though it should be included automatically by React Router):
<Route exact path="/" component={PageList}> <PageList {...props}/> </Route>
Nothing worked
I expect the output of console.log(...) to be the data passed via history.push. Considering the docs of react router that should work in that way.
Can anyone help?
-
MiDas over 4 yearsIf this comment is because of <Route exact path="/"> <PageList /> </Route> line in the OP's code then you are actually incorrect. This style was recently introduced so we can use hooks with react router dom. You can refer to the official blog post for more details reacttraining.com/blog/react-router-v5-1
-
Gaël S over 4 yearsGood point to mention indeed. But my answer was based on the fact that the OP was mixing the two syntaxes and did not mention
useLocation
hook which leads me to think that he was going for the "pre-hook" syntax. -
AxSch over 4 yearsThank you very much for your answer! I know that using the URL could be a solution for me. But I intended not to use the URL for passing the ID but location.state instead. This should work as well according to the docs.
-
AxSch over 4 years@MiDas: Thank you for your proposition. But is that not exactly what I wrote under "what I tried" No. 2 (besides the additional ">" which I guess is a typo).
-
AxSch over 4 years@MiDas: actually I was trying to use the "hook-syntax". as I am new to react maybe I did not use it consistently?
-
AxSch over 4 yearsSOLVED! Thank you a lot guys. I just tried the "useLocation-Hook" and now it works great!
-
MiDas over 4 years@AxSch sending state to a page this way is not advised as state will not be present on the page on reload. best to take the shared state and url param advice given below