Tony
Tony

Reputation: 219

ReactJS and AJAX Uncaught TypeError: Cannot Read Property 'bugs' of Undefined

I'm making AJAX request inside of a React function while making references to the state in the React class. However, I'm getting a TypeError where the reference to the state is undefined when I enter the AJAX request.

Here's my code snippet, I"m unsure how to proceed here. Where am I losing context?

class BugList extends React.Component {
    constructor() {
        super();
        this.state = {
            bugs: [],
        };
    }
    addBug(bug) {
        $.ajax({
            type: 'POST', url: '/api/bugs', contentType: 'application/json', data:JSON.stringify(bug),
            success: function(data) {
                var bug = data;

                var bugsModified = this.state.bugs.concat(bug);
                this.setState({bugs: bugsModified});
            }.bind(this),
            error: function(xhr, status, err) {
                console.log("error adding bug: ", err);
            }
        });
    }
    componentDidMount() {
        $.ajax('/api/bugs').done(function(data) {
            this.setState({bugs: data})
        }.bind(this));
    }
    render() {
        return(
            <div>
                <h1>Bug Tracker</h1>
                <BugFilter />
                <hr />
                <BugTable bugs={this.state.bugs}/>
                <hr />
                <BugAdd addBug={this.addBug}/>
            </div>
        );
    }
}

The problematic line in question:

var bugsModified = this.state.bugs.concat(bug);

The error log:

Uncaught TypeError: Cannot read property 'bugs' of undefined

Upvotes: 1

Views: 402

Answers (3)

Shubham Khatri
Shubham Khatri

Reputation: 281950

Even though you have bound the ajax success function you forgot to bind the addBug function

You can make use of arrow function to do that like

class BugList extends React.Component {
    constructor() {
        super();
        this.state = {
            bugs: [],
        };
    }
    addBug(bug) {
        $.ajax({
            type: 'POST', url: '/api/bugs', contentType: 'application/json', data:JSON.stringify(bug),
            success: function(data) {
                var bug = data;

                var bugsModified = this.state.bugs.concat(bug);
                this.setState({bugs: bugsModified});
            }.bind(this),
            error: function(xhr, status, err) {
                console.log("error adding bug: ", err);
            }
        });
    }
    componentDidMount() {
        $.ajax('/api/bugs').done(function(data) {
            this.setState({bugs: data})
        }.bind(this));
    }
    render() {
        return(
            <div>
                <h1>Bug Tracker</h1>
                <BugFilter />
                <hr />
                <BugTable bugs={this.state.bugs}/>
                <hr />
                <BugAdd addBug={(data) => this.addBug(data)}/>
            </div>
        );
    }
}

Upvotes: 0

Ankit Raonka
Ankit Raonka

Reputation: 6857

it is a scope issue, try..

addBug(bug) {
        ***var that = this;***
        $.ajax({
            type: 'POST', url: '/api/bugs', contentType: 'application/json', data:JSON.stringify(bug),
            success: function(data) {
                var bug = data;

                var bugsModified = ***that.state.bugs.concat(bug)***;
                this.setState({bugs: bugsModified});
            }.bind(this),
            error: function(xhr, status, err) {
                console.log("error adding bug: ", err);
            }
        });
    }

or you can also try

constructor() {
        super();
        this.state = {
            bugs: [],
        };
    this.addbugs = this.addbugs.bind(this);
    }

and keep the rest as it was

Upvotes: 1

Mayank Shukla
Mayank Shukla

Reputation: 104499

You need to bind the addBug method, use this:

<BugAdd addBug={this.addBug.bind(this)}/>

You are passing a method from parent component to child component, bind that method in parent component, like this:

<BugAdd addBug={this.addBug.bind(this)}/>

or you can define the binding in the constructor also, like this:

constructor() {
    super();
    this.state = {
        bugs: [],
    };
   this.addBug = this.addBug.bind(this);
}

and use directly:

<BugAdd addBug={this.addBug}/>

Upvotes: 1

Related Questions