dns_nx
dns_nx

Reputation: 3933

React - state property is undefined - Why?

I want to load all companies via AJAX request into a state property when the user clicks on the select box.

This is the code:

import React, { Component } from 'react';
import SelectOption from './SelectOption';

class CreateFreightEntryModal extends Component {
    
    constructor(props) {
        super(props);
        this.state = {
            freights: props.freights,
            onClose: props.onClose,
            onClick: props.onClick,
            companies: [],
        };
    }
    
    loadCompanies(event) {
        $.ajax({
            type: "POST",
            context:this,
            dataType: "json",
            async: true,
            url: "../data/get/json/companies",
            data: ({ 
                _token : window.Laravel.csrfToken,
            }),
            success: function (data) {
                var arr = $.map(data, function(el) { return el; });
                this.setState({
                    companies: arr
                })
            }
        });
    }

    render() {
        return (
            <div className="modal fade" id="createFreightEntryModal" tabIndex="-1" role="dialog">
                <div className="modal-dialog" role="document">
                    <div className="modal-content">
                        <div className="modal-header">
                            <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                            <h4 className="modal-title">New freight entry</h4>
                        </div>
                        <div className="modal-body">
                            <div>
                                <div>
                                    <form onSubmit={this.add.bind(this)}>
                                        <div className="row">
                                            <div className="col-xs-12 col-sm-12 col-md-12 col-lg-12">
                                                <strong>Create a new freight entry:</strong>
                                            </div>
                                        </div>
                                        <div className="row">
                                            <div className="col-xs-4 col-sm-4 col-md-4 col-lg-4">
                                                Company
                                            </div>
                                            <div className="col-xs-8 col-sm-8 col-md-8 col-lg-8">
                                                <div className="form-group" onClick={this.loadCompanies.bind(this)}>
                                                    <select className="selectpicker show-tick form-control" data-live-search="true" data-title="Please select" ref="Firma" required>
                                                    {
                                                        this.state.companies.map((company)=> {
                                                          return (
                                                            <SelectOption value={company.Nummer} displayValue={company.Bezeichnung} key={company.id} />
                                                          );
                                                        })
                                                    }
                                                    </select>
                                                </div>
                                            </div>
                                        </div>
                                        
                                        <div className="row">
                                            <div className="col-xs-12 col-sm-12 col-md-12 col-lg-12">
                                                <div className="form-group">
                                                    <button type="submit" className="btn btn-success"><span className="glyphicon glyphicon-floppy-disk"></span> Save </button>
                                                </div>
                                            </div>
                                        </div>
                                    </form>
                                </div>
                            </div>
                        </div>
                        <div className="modal-footer">
                            <button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

export default CreateFreightEntryModal

When I add the componentWillReceiveProps(nextProps) method, I get this error. This error occurs when the page is loaded and not when I click on the select box!

componentWillReceiveProps(nextProps) {
    this.setState({
        companies: nextProps.companies,
    });
}

TypeError: this.state.companies is undefined

This is the part where the error occurs:

...
this.state.companies.map((company)=> {
...

How can I solve this issue?

Upvotes: 1

Views: 1966

Answers (1)

pawel
pawel

Reputation: 36965

Using this construct:

componentWillReceiveProps(nextProps) {
    this.setState({
        companies: nextProps.companies,
    });
}

you update state.companies every time the component receives ANY props, even when there are no companies in the props. And when the nextProps don't have companies it is set to undefined.

Let's illustrate it this way:

{
  let props = { freights : [ 'a', 'b', 'c' ] }
  this.setState({ companies : props.companies }) 
  /* state.companies are now undefined, because props.companies are undefined */
}

Fix:

componentWillReceiveProps(nextProps) {
    if( nextProps.companies ){
      this.setState({
          companies: nextProps.companies,
      });
    }
}

BTW the problem with success callback scope I have mentioned in a comment may still apply.

Upvotes: 3

Related Questions