0

Say I had the following JSON file:

{
"farmer": [
{
"crops": "corn"
}
],
"activities":{
"hobbies": "swimming"
},
"name: Todd"
}

I would like to know how to make calls to them using React. My best attempt is as shown below.

componentDidMount: function(){
var selfish = this;
$.get('~~someurl~~', function(data){
selfish.setState(data);
});
},

render: function(){
return (<div>
<p>{this.state.name}</p>
<p>{this.state.activities.hobbies}</p>
<p>{this.state.farmer[0].crops}</p>
</div>)
}

I get that the first one {this.state.name} will run as it has been written. However, I am uncertain as to how to express the final two {this.state.activities.hobbies} and {this.state.farmer[0].crops} using the React syntax.

I have written them out in hopefully a way that expresses what I am trying to achieve with each call.

EDIT: The specific error that results from the latter two state that they are undefined.

EDIT: So I got the second one working by adding an empty initial state.

getInitialState: function(){
return {activities: '', farmer: ''}
}

However, this leaves the last one, which still returns an error.

5
  • 1
    Anything between the {...} is just normal JavaScript (there is no specific "React syntax"). this.state.activities.hobbies etc will work as long as the data exists. I assume that on the initial render the data doesn't exist. In that case you first have to think about how the UI should look like if the data is not present. Testing for the existence of the data / property works as usual, e.g. this.state.activities && this.state.activities.hobbies. There is nothing React specific about it. Commented Jul 18, 2016 at 16:45
  • Then I guess the question I have is how to go about loading these calls during page load, just as I would with {this.state.name}. Because {this.state.name} loads just as soon as I render. Commented Jul 18, 2016 at 16:54
  • 1
    They are executed on initial render. But because this.state.activities doesn't exist the first time, you will get an error. So you either have to check beforehand whether the value exist (and render something depending on that check) or you have to provide a default state to the component, e.g. with an empty this.state.activities object. Here is a simplified example of the issue you are experiencing: var state = {}; console.log(state.activities.hobbies); This will throw an error because state doesn't have any properties. Now, I can either add an initial value or test before logging. Commented Jul 18, 2016 at 17:04
  • Cool. I took what you said and returned an empty activities on initial load. Now, I'm still unsure of the last part {this.state.farmer[0].crops}. Having an empty farmer: '' on initial state does not solve this. Commented Jul 18, 2016 at 17:18
  • 1
    Well, this.state.farmer[0].crops expects farmer to be an an array containing an object. farmer: '' sets farmer to an empty string instead. Type var farmer = ''; console.log(farmer[0]) in your browser's console and see what the result is. If you go with the default state, then you need to initialize the state with values similar to the ones you expect. Commented Jul 18, 2016 at 17:21

1 Answer 1

1

The problem is that you are using componentDidMount when you should use componentWillMount. Check out the documentation on these lifecycle methods.

This is what the documentation says about componentDidMount

Invoked once, only on the client (not on the server), immediately after the initial rendering occurs.

Which means when you first render your states are not declared unless you have used getInitialState before (another lifecycle method).

I simply did this:

componentWillMount: function () {
    this.setState({
        "farmer": [
            {
            "crops": "corn"
            }
        ],
        "activities":{
            "hobbies": "swimming"
        },
        "name": "Todd"
    });
},

and I was able to use this.state.farmer[0].crops in my render method

EDIT:

To be clear. If you need to retrieve the data after you rendered the component then you need to specify default values for the states that you use in render. This can be achieved using getInitialState:

getInitialState: function () {
    return {
        "farmer": [
            {
                "crops": DEFAULT_VALUE
            }
        ],
        "activities":{
            "hobbies": DEFAULT_VALUE
        },
        "name": DEFAULT_VALUE
    });
},
Sign up to request clarification or add additional context in comments.

3 Comments

So I am trying to place an empty initial state. Where I did activities: '', how would I do that for farmer[0].crops?
This is the wrong solution. Using componentDidMount is correct, since the OP is making an Ajax request. Using componentWillMount won't help here. I mean, you can use it, but it won't help, since Ajax is asynchronous. If you want to provide an initial state, do that with getInitialState.
In the answer I also mention that to have them declared before you can use getInitialState. I am taking a broader approach to explaining what to do

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.