3

I'm using react, alt.js, and react-router, and building an application with basic CRUD. There is a menu item for "Create Item", and it brings up a modal (using react-bootstrap...) and on submit it fires an action to create some model on the backend, and then does a browserHistory.push (as recommended in react-router docs) when that completes go to the item page for the newly created item.

So in the basic case, this works. For example if I'm on the main app page it works. However, if I was already on the item detail page for a different item (let's say I was on /item/1 and I just created /item/2, so I'm trying to redirect to /item/2 from page /item/1).

And my async load logic (well, the action call at least, for fetchItem) is in componentDidMount of the ItemViewPage react component, which seems pretty typical based on all the examples I can find online.

And the problem is, if the page was currently already rendered, componentDidMount never gets called, because the component is already mounted(!). And so my page URL updates to /item/2, but the contents are still for /item/1.

So, my question is....Yeah. Am I wrong to initiate data load from componentDidMount? Am I supposed to do it some other lifecycle method (say, componentWillReceiveProps, since the react router will set a new id)? Or is there some other place entirely where I should be firing off data load from (e.g. does react-router have some feature I'm not aware of that handles this)?

Kevin
  • 24,871
  • 19
  • 102
  • 158
  • [`ShouldComponentUpdate`](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate) is my guess, but it's probably best if you post some code. – U r s u s Jun 30 '16 at 21:36
  • it would be a lot of code, probably! But anyway just typing out the question led me to try `componentWillReceiveProps`, and I test there for `if (this.props.params.id !== newProps.params.id) { this.props.fetchItem(newProps.params.id); }`, which seems to work. It makes sense I guess, but it caught me by surprise that it doesn't work out of the box. – Kevin Jun 30 '16 at 21:39
  • How would it work "out of the box" without knowing your `params`? Anyways, glad you got it working. Perhaps next time, do more research before posting a question ;) – U r s u s Jun 30 '16 at 21:48
  • `componentDidMount` is only fired when the component is mount the first time. So `componentWillReceiveProps` is effectively the right way to go here. – Pierre Criulanscy Jun 30 '16 at 21:52
  • 1
    Most examples online don't mention this. And it's a little weird (at least I think) that you have to duplicate your load logic in two different life cycle methods. – Kevin Jun 30 '16 at 21:56
  • I guess, the reason it's surprising is that I come from a server side render world, where `/item/1` and `/item/2` are actually two different pages. And with a client side router, its the same react component just receiving a different id property. – Kevin Jun 30 '16 at 21:59

1 Answers1

2

Since React is smart and knows that you re-use the component for your route, the component will remain mounted. The lifecycle method of your choice will not be able to handle the job, since it gets called on the initial mounting of the component, once.

I would advise you to use componentWillReceiveProps and in there you can check if, let's say, the id field of your item changed. That means you should probably update since there's new, different data to render.

Elod Szopos
  • 3,475
  • 21
  • 32