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

前端 未结 3 863
温柔的废话
温柔的废话 2021-01-04 22:46

I have a universal react app that\'s using redux and react-router.

I have several routes as follows:

/2016
/2015
/2014
/2013

etc.

相关标签:
3条回答
  • 2021-01-04 23:20

    The 'lifecycle' hook onEnter and onChange has been removed in React-router 4 which makes most of the other answers to this question out-dated.

    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

    0 讨论(0)
  • 2021-01-04 23:24

    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:

    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.

    Edit: This applies to an old, no longer supported version of react-router.

    0 讨论(0)
  • 2021-01-04 23:32

    I prefer to have actions dispatched from the render prop itself:

    <Route to="path" render={ props => {
      this.props.toggleInfoLayer(true);
      return <UserInfo />;
    }} />
    

    This is assuming you are using Redux's mapDispatchToProps argument.

    I tried using the history change event handler as mentioned in the accepted answer, but I found it undesirable to be dispatching actions from a rogue file. One more place I had to think about, when Redux already provides plenty too many.

    0 讨论(0)
提交回复
热议问题