React Router + Redux - Dispatch an async action on route change?

Multi tool use
React Router + Redux - Dispatch an async action on route change?
I have a universal react app that's using redux and react-router.
I have several routes as follows:
/2016
/2015
/2014
/2013
etc.
Each route requires data from an API. Currently, i have the <Link>
elements in the Navigation component dispatch an async action onClick
, which populates the store with data from the API for that route.
<Link>
onClick
For MVP, i'm just overwriting the post: {}
contents in the store with the new post contents when the route changes, that way we get any new content that was on the API.
post: {}
I've realise that having the action dispatchers on the <Link>
buttons isn't optimal, as hitting the back button does not re-trigger the action dispatch to get the content for the previous route.
<Link>
Is there a way to get React Router to trigger the dispatch action anytime a route change occurs? (Limiting it to listen to a specific set of routes would be a bonus).
I realise i should be getting the history from the store, but for now, it's easier to hit the API again by triggering an action dispatch in order to get the new content.
Cheers.
2 Answers
2
Yeah React Router has onEnter and onLeave hooks. You could build your routes to take your store
instance, so you can access it in those helpers:
store
const createRoutes = (store) => {
const fetchPosts = () => store.dispatch({
types: ['FETCH_POSTS', 'FETCH_POSTS_SUCCESS', 'FETCH_POSTS_FAIL',
url: '/posts'
});
return (
<Route path="/" component={App}>
<Route path="posts" component={PostList} onEnter={fetchPosts}/>
<Route path="posts/:id" component={PostDetail} />
</Route>
)
}
A better solution is to use something like redial
or redux-async-connect
. This allows you to co-locate your component's data dependencies with your components, while retaining the ability to test your components without touching the network.
redial
redux-async-connect
Nice!! I couldn't get Redial to work (for some reason the hooks weren't firing, and the promise was resolving instantly), so i've implemented your example while i try and use an alternative. Works!
– Scotty
May 24 '16 at 20:37
Is this undocumented or only for older versions of react-router? I couldn't find any mention of the
onEnter
and onLeave
hooks in the documentation.– Håken Lid
Jun 8 at 18:08
onEnter
onLeave
@HåkenLid unfortunately this is outdated. Posting an updated answer
– Matthew Barbara
Jun 29 at 21:44
You should edit this answer instead. Or at least add an explanation of which version of react router it applies to.
– Håken Lid
Jul 1 at 10:19
The 'lifecycle' hook onEnter
and onChange
has been removed in React-router 4 which makes the accepted answer out-dated.
onEnter
onChange
Whilst I recommend you to use your components lifecycle methods to achieve your goal, here is an answer to your question which works on React-router 4.
What works today is listen to the history change using History library created by the developers of React router themself and dispatch async actions from there.
// history.js
import createHistory from "history/createBrowserHistory"
const history = createHistory()
// Get the current location.
const location = history.location
// Listen for changes to the current location.
const unlisten = history.listen((location, action) => {
//Do your logic here and dispatch if needed
})
export default history
Then import the history in your application
// App.js
import { Router, Route } from 'react-router-dom';
import Home from './components/Home';
import Login from './components/Login';
import history from './history';
class App extends Component {
render() {
return (
<Router history={history}>
<div>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
</div>
</Router>
)
}
}
Source: History library
React router docs
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
The accepted answer does not work on react-router 4. I've answered a solution which works with v4. If you think my answer is good you can accept my answer as it will help fellow developers finding their solution faster.
– Matthew Barbara
Jun 29 at 22:43