26

If I have a React component that requires some setup (e.g. for timers, or WebAudio API, etc), I'm having trouble deciding whether the initialization should go in constructor or componentWillMount. Is there any advantages or disadvantages to either one? It's not clear to me which one is the better place for this.

I Googled around a bit to see if anyone had discussed the differences between constructor and componentWillMount but I couldn't find anything.

EDIT: Redux and any asynchronous functions should not be part of the equation.

ffxsam
  • 26,428
  • 32
  • 94
  • 144
  • Per the documentation, this should go in `componentDidMount`: https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount "If you want to....set timers...or setInterval...perform those operations in this method." – lux Jul 01 '16 at 15:18

2 Answers2

29

Normally the only thing you do in the constructor is assign your initial this.state if your component is stateful. You should not do anything else in the constructor.

componentWillMount is generally unnecessary. I would say in most cases its use is an anti-pattern. One reason people use it is for updating the state from an external source one last time before rendering but technically assigning it in the constructor is equivalent. The only minor convenience it affords is that you can setState inside it but you can’t inside the constructor.

For any side effects (data fetching or DOM manipulation) you should use componentDidMount.

Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
  • It seems if I'm building a higher-order component, I need to set things up in `componentWillMount`. Just as a test, I renamed `WillMount` to `DidMount` and I got an error in my wrapped component about a prop not existing (which is passed into it from the HOC's state). Maybe HOCs are a special case where `componentWillMount` is a better place to initialize and one has to set state based on a bunch of code execution? (specifically referring to [this code](https://github.com/ffxsam/formous/blob/master/src/index.js#L35-L62)) – ffxsam Jul 05 '16 at 22:02
  • 1
    There is no difference whether you build a HOC or not. HOC is just a function that returns a component. This component is no different from any other components, and so the same rules apply. In your code, you want to move the logic for calculating the initial state into your constructor. Instead of calling `setState` you would assign it to `this.state`. – Dan Abramov Jul 05 '16 at 22:08
  • Ahh, so the constructor is an appropriate place for all that setup code. I wasn't sure. I kept going back and forth whether it belonged in `constructor` or `componentDidMount`.. hence this post. :) So, I get why DOM manipulation wouldn't work in the constructor, but what's wrong with data fetching? – ffxsam Jul 05 '16 at 22:11
  • 1
    It's a side effect. Side effects should not be placed in constructor. There is no reason why this is “bad” per se, but that's the intended usage pattern. When constructor runs it isn't a guarantee that the component will be mounted soon (in practice it will but this may change in the future). So please don't perform side effects in constructor. – Dan Abramov Jul 05 '16 at 23:49
  • Also I am not fully sure what you mean by "all that setup code". I said in the answer that **the only thing constructor is appropriate for is to specify the initial state**. This is what I suggested to move into constructor. I do not suggest moving anything else into the constructor. – Dan Abramov Jul 05 '16 at 23:52
  • Ok.. right. So that leaves me back where I started, putting my initialization code (determining initial field & form validity) in `componentWillMount`, because it doesn't belong in `constructor`, and if I put it in `componentDidMount`, then the wrapped component doesn't get HOC's state data (passed via props) it needs at the right time. Sorry if any of this is unclear, I find it difficult to discuss code.. much easier to just show it. :) – ffxsam Jul 05 '16 at 23:58
  • I don't understand. What you describe ("determining form validity") **is** your state initialization code. So it is fine to put it in constructor. I didn't say it has to be a single line. I only said you shouldn't do side effects like AJAX there. – Dan Abramov Jul 06 '16 at 01:27
  • I don't know what you mean by "all that setup code". If you told me what exact code you were referring to I could have told you whether it's okay to put it in constructor. I didn't mean anything in particular. But as long as it's just **a calculation** (rather than a side effect) necessary to **compute the initial state** it is fine to do it from constructor, whether you do it inline, call another method or write it in any other way. – Dan Abramov Jul 06 '16 at 01:30
  • I definitely need to do some refactoring! The form/field validity checks depend on a few vars in state, and then when those checks are done, it initializes state. It's a simple fix, I was just in a bit of a rush when I wrote it. If you're curious, you can see the latest code [here](https://github.com/ffxsam/formous/blob/master/src/formous.js). – ffxsam Jul 06 '16 at 01:32
  • So for example, if I move the code from `componentWillMount` into `constructor`, you can see how it would cause a problem. `this.testField` is called _before_ the state is set in the constructor, and `testField` makes assumptions about fields set in the state...which isn't set yet. It's just a bit of messy coding I need to clean up. But everything you've said makes total sense. – ffxsam Jul 06 '16 at 01:39
  • Yes, you'd need to fix some assumptions. – Dan Abramov Jul 07 '16 at 01:47
  • Thanks for chiming in, I appreciate your time! – ffxsam Jul 07 '16 at 03:44
1

If you want to call some flux action (for ajax calls) use componentWillMount or componentDidMount.

You can initialize state in constructor

Piyush.kapoor
  • 6,715
  • 1
  • 21
  • 21