I'm trying to programmatically push an URL to navigate with react-router, redux, and connected-react-router
When clicking on a <Link />
button, it's working great, the URL is changing and the route too.
But when using a dispatch(push(url))
, the URL only change and the content is not updated
I've made a minimal example here.
Any help would be really grateful,
Thanks
The react-router-dom package is great for rendering different React components based on the url path. Therefore, React components can lead to others by changing the url path.
You can use the connected-react-router library (formerly known as react-router-redux ). Their Github Repo details the steps for the integration. Once the setup is complete, you can now access the router state directly within Redux as well as dispatch actions to modify the router state within Redux actions.
You can either push a new record onto the top of the history stack or you can replace the top record. If you use push , and then hit the browser's back button, it will take you back to the page you are currently on, but if you use replace it will take you two pages back.
So in a nutshell, the Link component is responsible for the transition from state to state (page to page), while the Route component is responsible to act as a switch to display certain components based on route state.
A lot of anti-pattern code, poor application structured, and mixing of packages is holding your application back.
I rewrote it entirely, here's what I've done:
Router
(BrowserRouter
) with ConnectedRouter
.components
within the App.js
file.Header
is always mounted, you don't need redux
, instead you can just use withRouter
(it exposes route props to the component).rootReducer
is missing a reducer
, so I added a dummyReducer
that just returns state
.Link
or this.props.history
when navigating. For this example, there's no need to use both. Also, you don't need to use ConnectedRouter
's push
function, because the history
is passed as a prop when using withRouter
.Side note: If you want the Header
to be a "router" where all route changes pass through here, then you'll need to create an action
and a reducer
that passes a string
and stores it to the redux's store
. The Header
is then connect
ed to the redux store and updates the route
when this string
has changed.
Working example: https://codesandbox.io/s/526p7kjqq4
components/Header.js
import React, { PureComponent, Fragment } from "react";
import { withRouter } from "react-router-dom";
class Header extends PureComponent {
goTo = route => {
this.props.history.push(route);
};
render = () => (
<Fragment>
<ul>
<li>
<button onClick={() => this.goTo("/")}> Announcements </button>
</li>
<li>
<button onClick={() => this.goTo("/shopping")}> Shopping </button>
</li>
</ul>
<div>
<button onClick={() => this.goTo("/shopping")}>
Click here to go shopping ! (if you can...)
</button>
</div>
</Fragment>
);
}
export default withRouter(Header);
routes/index.js
import React from "react";
import { Switch, Route } from "react-router-dom";
import Announcements from "../components/annoucements";
import Shopping from "../components/shopping";
export default () => (
<div style={{ padding: "150px" }}>
<Switch>
<Route exact path="/" component={Announcements} />
<Route path="/shopping" component={Shopping} />
</Switch>
</div>
);
components/App.js
import React, { Fragment } from "react";
import Routes from "../routes";
import Header from "./Header";
export default () => (
<Fragment>
<Header />
<Routes />
</Fragment>
);
Here is what you're trying to accomplish: https://codesandbox.io/s/8nmp95y8r2
However, I DO NOT recommend this as it's a bit unnecessary, when history
is either already passed as a prop from the Route
or can be exposed when using withRouter
. According to the Redux docs, it's not recommended either. And instead to either use Link
or pass the history
prop to the redux action
creator instead of programmatic navigation through redux state.
containers/Header.js
import React, { PureComponent, Fragment } from "react";
import { connect } from "react-redux";
import { push } from "connected-react-router";
class Header extends PureComponent {
goTo = route => this.props.push(route); // this is equivalent to this.props.dispatch(push(route)) -- I'm just appending dispatch to the push function in the connect function below
render = () => (
<Fragment>
<ul>
<li>
<button onClick={() => this.goTo("/")}> Announcements </button>
</li>
<li>
<button onClick={() => this.goTo("/shopping")}> Shopping </button>
</li>
</ul>
<div>
<button onClick={() => this.goTo("/shopping")}>
Click here to go shopping ! (if you can...)
</button>
</div>
</Fragment>
);
}
export default connect(
null,
{ push }
)(Header);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With