Giorgia Sambrotta
Giorgia Sambrotta

Reputation: 1223

Why is this.props undefined in my ReactJS code?

On my way to learn React and ES6, I took the official tutorial and played around to make it ES6 compatible. But when it comes to executing the Ajax request, I get the following error:

CommentBox.js:23 Uncaught TypeError: Cannot read property 'url' of undefined

Here is my CommentBox file/code:

import React from 'react';
import CommentList from './CommentList.js';
import CommentForm from './CommentForm.js';

export default class CommentBox extends React.Component {
  constructor(props) {
    super(props);
    console.log(this.props)
    this.state = {
      data: []
    }
  }

  loadCommentsFromServer() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  }

  handleCommentSubmit(comment) {
    let comments = this.state.data;

    // Optimistically set  id on the new comment.
    // It will be replaced by an id generated by the server.
    // In a production you would have a more robust system in place.
    comment.id = Date.now();
    let newComments = comments.concat([comment]);
    this.setState({data: newComments});
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      type: 'POST',
      data: comment,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        this.setState({data: comments});
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  }

  componentDidMount() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  }

  render() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }
}

The error happen on loadCommentsFromServer; it seems not to know what this.props is. I thought it was a this reference problem and found a similar question where it is suggested to use new ES6 arrows to fix the issue. I then tried: loadCommentsFromServer = () => {}, but Browserify complains and doesn't build.

Upvotes: 1

Views: 2322

Answers (2)

Aaron Beall
Aaron Beall

Reputation: 52133

I thought it was a this reference problem and googling around i found a similar stackoverflow question where they suggest to use new ES6 arrows to fix the issue. I try then to use: loadCommentsFromServer = () => {} but browserify complain and don't build :/

ES6 arrow functions will indeed solve your problem. The build error is because ES6 does not support class properties, and loadCommentsFromServer = is a class property initializer. Enable ES7 class properties and you should be able to do this and it will solve your problem without needing to manually bind or wrap your callback in a new fat arrow function when you call setInterval.

Upvotes: 1

WickyNilliams
WickyNilliams

Reputation: 5298

This line is your problem:

setInterval(this.loadCommentsFromServer, this.props.pollInterval);

You are passing the method loadCommentsFromServer to setInterval, but it will be invoked without context therefore this will no longer bound to your component (this will be bound to the window). Instead you should do something like this:

setInterval(this.loadCommentsFromServer.bind(this), this.props.pollInterval);
// OR... use a fat arrow, which preserves `this` context
setInterval(() => this.loadCommentsFromServer(), this.props.pollInterval); 

Finally, you should store the interval id, so that you can clear it when your component is unmounted:

componentDidMount() {
  this.loadCommentsFromServer();
  this.intervalId = setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},

componentWillUnmount() {
   clearInterval(this.intervalId);
}

Upvotes: 6

Related Questions