3

I run frequently into problem while using React in a specific way.

I have a hierarchy of components. The application state lives in the common owner uppermost component. I set initial state with empty objects, or arrays whatever in getInitialState. I fetch data via ajax with calling a method of this state owner uppermost component in this component's componentDidMount. But whether I use the state set in the success callback of the ajax call in this same component, or in sub components, by passing the state to them via props, I almost always get a variable can't find or something undefined sort of errors.

Thinking conceptually, the render method invoked when I mount the components, so it will not find data in the variables embedded in it. But we have getInitialState. This seems ok but what if the nested objects are being used in the render methods. States in the getInitialState are just empty objects, so references to the to be sub elements are undefined.

Even using componentWillMount does not work. Only way seems having initial states and not to reference any undefined sub elements of those in the render. However it seems necessary in most cases. Is the issue related to this necessity I see being actually an anti-pattern.

I have found React very useful for me at first tutorials and simpler cases, but now I cannot make use of it efficiently.

How to counter this behaviour correctly and in the best practice possible?

sçuçu
  • 2,960
  • 2
  • 33
  • 60

1 Answers1

2

FIRST SOLUTION: The method I use is simply check is the state exists in the render function

render: function() {
    var result = { this.state.field ?
        this.state.field.embeddedfield ?
            <div> this.state.field.embeddedfield </div>
        : <div> Data are loading! </div>

      : "" }
    return {result};
}

SECOND SOLUTION If you want your data to be ready before rendering you need to execute the first fetch outside :

  $.ajax({...}).success(function(res) {
         <MyView data={res} /> // render your function on success
    });

See this : bind(this) not working on ajax success function

To answer about why componentWillMount won't work:Putting ajax call in componentWillMount won't work because it won't wait for your call to be fetched and cycle concurrency may also occurs.

Community
  • 1
  • 1
François Richard
  • 6,817
  • 10
  • 43
  • 78
  • It may be useful, but clearly there must be a better way, this is diffucult to use. componentWillMount should be able to do it. But it seems not. I do not understand why. – sçuçu Sep 17 '15 at 00:53
  • componentWillMount won't call the render function is state is changed inside it (see doc). The other solution is to properly define your initiale state with all the nested objects. I add the same problem and didn't find a better way, actually I asked the very same question on SO asking if there was a lighter way but people confirmed they were doing it that way indeed. Maybe you'll get lucky and find a better answer(I would be very intersted in it!) but for now I think there is no other way. To make it cleaner you can still take the states check in a function but conceptually this is it. – François Richard Sep 17 '15 at 00:57
  • I do not mean componentWillMount will call the render function. render function will be happily called whenever state changes, e.g. in componentWillMount, or in componentDidMount. I mean componentWillMount ensure that the render have not been called yet, so I can fetch data and ensure the data is ready for render function before it is called with all its structure, nested etc. This is what is meant in docs for [componentWillMount](https://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount). But I do not get why I cannot get it work. – sçuçu Sep 17 '15 at 01:02
  • And again for recalling render when state changes, a setInterval is easily called in the componentDidMount separately. This is another thing. – sçuçu Sep 17 '15 at 01:05
  • So first solution you are checking inside if data has arrived, second one you render when you are sure that your data are here. I doubt there is any other solutions but if you find one pleas let me know cause I have dug this problem a little bit. – François Richard Sep 17 '15 at 01:13
  • Putting ajax call in componentWillMount won't work because it won't wait for your call to be fetched and cycle concurrency may also occurs. – François Richard Sep 17 '15 at 01:23
  • I did not understand this last one clearly. Does componentWillMount not wait until ajax call reached to success or error callbacks and executed them, so, for example a setState has occurred in the success callback of this ajax call, which will make it work in the way I have expected? And your second solution, is it MyView the root component of an entire React app? That would do it. – sçuçu Sep 17 '15 at 01:39
  • besides, I have another problem that in an component which got data via props, a state of parent component, I can dig into some level of nesting in some components and not so in another data similar structure. I wondr if this also have something to do with the same not ready problem. – sçuçu Sep 17 '15 at 01:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/89867/discussion-between-isik-and-francois-richard). – sçuçu Sep 17 '15 at 02:39
  • why not make the first ajax fetch in the getInitalState? – sçuçu Sep 17 '15 at 02:41