55

I'm using Redux, redux-router and reactjs.

I'm trying to make an app where I fetch information on route change, so, I've something like:

<Route path="/" component={App}>
    <Route path="artist" component={ArtistApp} />
    <Route path="artist/:artistId" component={ArtistApp} />
</Route>

When someone enters to artist/<artistId> I want to search for the artist and then render the information. The question is, what it's the best way of doing this?

I've found some answers about it, using RxJS or trying a middleware to manage the requests. Now, my question is, Is this really necessary or just a way to keep the architecture react-agnostic? Can I just fetch the information I need from react componentDidMount() and componentDidUpdate() instead? Right now I'm doing this by triggering an action in those functions that request information and the component re-renders when the information has arrived. The component has some properties for letting me know that:

{
    isFetching: true,
    entity : {}
}

Thanks!

Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
Franco Risso
  • 1,572
  • 2
  • 13
  • 18

3 Answers3

64

Now, my question is, Is this really necessary or just a way to keep the architecture react-agnostic? Can I just fetch the information I need from react componentDidMount() and componentDidUpdate() instead?

You can totally do that in componentDidMount() and componentWillReceiveProps(nextProps).
This is what we do in real-world example in Redux:

function loadData(props) {
  const { fullName } = props;
  props.loadRepo(fullName, ['description']);
  props.loadStargazers(fullName);
}

class RepoPage extends Component {
  constructor(props) {
    super(props);
    this.renderUser = this.renderUser.bind(this);
    this.handleLoadMoreClick = this.handleLoadMoreClick.bind(this);
  }

  componentWillMount() {
    loadData(this.props);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.fullName !== this.props.fullName) {
      loadData(nextProps);
    }

  /* ... */

}

You can get more sophisticated with Rx, but it's not necessary at all.

Ross Allen
  • 43,772
  • 14
  • 97
  • 95
Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
21

I've did this with custom binding on plain router onEnter/onLeave callback props like this:

const store = configureStore()

//then in router
<Route path='/myRoutePath' component={MyRouteHandler} onEnter={()=>store.dispatch(myRouteEnterAction())} />

It's a bit hacky but works, and I don't know better solution right now.

Victor Suzdalev
  • 2,202
  • 19
  • 28
  • Thanks for the solution! It works, although I prefer the approach of Dan for keeping things in the same component, I think it's cleaner. – Franco Risso Oct 04 '15 at 14:19
  • @FrancoRisso as a matter of taste, and not to argue here )))) – Victor Suzdalev Oct 05 '15 at 10:19
  • 1
    This is a good alternative (that I prefer most of the time). If you want your components to be stupid enough to not know how to fetch data, this is how you do it. I like when components only render and "react" to props changes. If instead the component as a state that involves an API call that's opaque to the rest of the app (ex: github star counter you publish on npm) it makes more sense to componentWillMount () => loadData. Cheers! – kilianc May 19 '16 at 16:12
  • 2
    onEnter no longer exists on react-router-4 – igo Feb 27 '18 at 17:05
4

1) dispatching optimistic request actions on route changes, i.e. BrowserHistory.listen(location => dispatch(routeLocationDidUpdate(location)));

2) Async Actions: http://redux.js.org/docs/advanced/AsyncActions.html

Ashik Nesin
  • 1,848
  • 1
  • 10
  • 7
Dennis Krupenik
  • 666
  • 5
  • 18