I've seen several of these questions on Stack Overflow, but none of the fixes seem to work. this.props.location.state
always returns undefined. Here is my AppContainer
, ExamplePageParent
, and ExamplePage
.
import {Router, Route, Switch} from "react-router-dom";
class AppContainer extends Component {
render() {
return (
<Router>
<Switch>
<Route exact path="/page" component={Page}
<Route exact path="/examplePage" component={ExamplePage}/>
</Switch>
</Router>
)
}
}
//has mapStateToProps and mapDispatch to Props here
export default connect(mapStateToProps, mapDispatchToProps)(AppContainer);
--
class Page extends Component {
render() {
return(
<AnotherPage key=this.props.id>
);
}
}
// has mapStateToProps here (this.props.id comes from here)
export default connect(mapStateToProps, mapDispatchToProps)(Page);
--
class AnotherPage extends Component {
render() {
return(
<ExamplePageParent key=this.props.id>
);
}
}
// has mapStateToProps here (this.props.id comes from here)
export default connect(mapStateToProps, null)(AnotherPage);
--
class ExamplePageParent extends Component {
//pathName and dataPassed content filled, not relevant to question
render() {
return(
<Link
class={'link-styling'}
target="_blank"
rel="noreferrer"
to={{pathname: this.state.pathName, state: {dataPassed: true} }}
>
Click Me
</Link>
);
}
}
//has mapStateToProps here
export default connect(mapStateToProps, null)(ExamplePageParent);
--
import {withRouter} from "react-router";
class ExamplePage extends Component {
constructor(props) {
super(props);
//this has content:
console.log(this.props.location);
//undefined:
console.log(this.props.location.state);
}
render() {
return(
// do stuff
);
}
}
export default withRouter(ExamplePage);
Router
which needs a history
object to have a defined location
object to work with.To address the undefined location
you have a couple options:
Import a custom history creator from the history
package:
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
...
<Router history={history}>
...
</Router>
Use one of the higer-level routers, i.e. BrowserRouter
, HashRouter
, MemoryRouter
, etc...:
import { BrowserRouter as Router } from 'react-router-dom';
...
<Router>
...
</Router>
To address accessing the "state" in the receiving component you'll need to add a bit of logic. When the app is started in a new window/tab the state isn't transferred, so to combat this you can send the route state serialized as a queryString search param.
<Link
className={"link-styling"}
target="_blank"
rel="noreferrer"
to={{
pathname: this.state.pathName,
search:
"stuff=content&moreStuff=moreContent" + // existing search params
"&dataPassed=This is the passed data.", // additional for state
state: { dataPassed: "This is the passed data." }
}}
>
Click Me
</Link>
And then in ExamplePage
process the queryString to extract and delete the added "dataPassed"
query param, and redirect with populated route state previously existing queryString.
class ExamplePage extends Component {
componentDidMount() {
const { history, location } = this.props;
const { pathname, state, search } = location;
console.log({ location });
const searchParams = new URLSearchParams(search);
let dataPassed;
if (searchParams.has("dataPassed")) {
dataPassed = searchParams.get("dataPassed");
searchParams.delete("dataPassed");
}
history.replace({
pathname,
search: searchParams.toString(),
state: { dataPassed }
});
}
render() {
return (
...
);
}
}