React js: Can´t send first object in array as prop

Im trying to build an small React.js application and my component structure looks like this:

MainComponent
    - CategoryList
        -Category
    - ItemsList 
        -Item

My MainContent component does an ajax request for its state data in the componentDidRender: which returns this object:
data:[
Object[0]
 -name
 -items[]
,
Object[1],
Object[2]
]

Now, I want my CategoryList to write out all the Categories by name, which works just fine, but I also want to print out the items of the selected category. This is my ItemsList component:
 var ItemsList = React.createClass({
    render:function(){

         var itemNodes = this.props.category.items.map(function(item){
            return (
                <Item name={item.name} />
            );
        });

        return(
            <div className="itemList">
            {itemNodes}
            </div>
        );
    }
});

And this is how I pass on the “category”-property from my the parent component
<ItemsList category={this.state.data[0]} />

I get an error say “Can´t read property items of undefined” meaning that the category prop never was assigned. I know that this.state.data contains an array of objects so I don´t see the error here.

What do I do wrong?

EDIT: Per request, this is my MainComponent:

var MainComponent = React.createClass({
    getInitialState:function(){
        return {data: []};
    },
    componentDidMount:function(){
        $.ajax({
            type:'get',
            url: '/categories',
            dataType: 'json',
            success:function(data){
                this.setState({data: data});
            }.bind(this)

        });
    },
    render: function(){
        return (
        <div className="row">
            <div className="col-md-6">
                <CategoryList categories={this.state.data} />
            </div>
            <div className="col-md-6">
            <ItemsList category={this.state.data[0]} />
            </div>
        </div>

        );
    }
});

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Your main component initializes the state with an empty array in data. A render would always fail because there is no this.state.data[0].

One would probably reply that the ajax request will provide the value for this state property data (supposing that your web service is providing a valid array). However, this only happens after the response was received from the server, which will not happen after the first render.

If the information was available immediately, one could either setState on the method componentWillMount or the component constructor, so as to avoid triggering a second render:

componentWillMount() is invoked immediately before mounting occurs. It
is called before render(), therefore setting state synchronously in
this method will not trigger a re-rendering. Avoid introducing any
side-effects or subscriptions in this method.

In this case, since we are waiting for remote information, the React documentation still recommends the use of componentDidMount, as well employed here:

componentDidMount() is invoked immediately after a component is
mounted. Initialization that requires DOM nodes should go here. If you
need to load data from a remote endpoint, this is a good place to
instantiate the network request. Setting state in this method will
trigger a re-rendering.

Therefore, the component’s render method must be able to handle the missing state variable. There are multiple ways to approach this, but preventing the nested element from being rendered until we have data is the easiest approach. With some additional logic, the application could inform the user that the particular component is loading.

render() {
    return (
    <div className="row">
        <div className="col-md-6">
            <CategoryList categories={this.state.data} />
        </div>
        <div className="col-md-6">
          {this.state.data.length > 0 &&
            <ItemsList category={this.state.data[0]} />
          }
        </div>
    </div>
    );
}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x