monk
monk

Reputation: 97

Why is this.refs undefined?

Why is this.refs undefined in the code below?

class NewItem extends React.Component {
  handleClick() {
    console.log(this.refs) //prints out undefined
    const name = this.refs.name.value;
    const description = this.refs.description.value;
    $.ajax({
      url: 'api/v1/items',
      type: 'POST',
      data: {
        item: {
          name: name,
          description: description
        }
      },
      success: (item) => {
        this.props.handleSubmit(item);
      }
    });
  }

  render() {
    return (
      <div>
        <input ref='name' placeholder='Enter the name of the item' />
        <input ref='description' placeholder='Enter the description of the item' />
        <button onClick={this.handleClick}>Submit</button>
      </div>
    )
  }
}

Upvotes: 2

Views: 10496

Answers (3)

TRomesh
TRomesh

Reputation: 4481

You havens bind the functions. it should be done like this

class NewItem extends React.Component {

    constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
    }

  handleClick() {
    console.log(this.refs) //prints out undefined
    const name = this.refs.name.value;
    const description = this.refs.description.value;
    $.ajax({
      url: 'api/v1/items',
      type: 'POST',
      data: {
        item: {
          name: name,
          description: description
        }
      },
      success: (item) => {
        this.props.handleSubmit(item);
      }
    });
  }

  render() {
    return (
      <div>
        <input ref='name' placeholder='Enter the name of the item' />
        <input ref='description' placeholder='Enter the description of the item' />
        <button onClick={this.handleClick}>Submit</button>
      </div>
    )
  }
}

Try using the ES6 features, The arrow functions to avoid this binding issue. like this.

  handleClick =()=> {
    console.log(this.refs) //prints out undefined
    const name = this.refs.name.value;
    const description = this.refs.description.value;
    $.ajax({
      url: 'api/v1/items',
      type: 'POST',
      data: {
        item: {
          name: name,
          description: description
        }
      },
      success: (item) => {
        this.props.handleSubmit(item);
      }
    });
  }

Upvotes: 0

Chris
Chris

Reputation: 59511

You need to bind this to your handleClick() function, like this:

<button onClick={this.handleClick.bind(this)}>Submit</button>

or through the constructor, like this:

constructor(props) {
  ...
  this.handleClick = this.handleClick.bind(this);
}

Though you should avoid using string literals in refs. This approach is deprecated.

Legacy API: String Refs

If you worked with React before, you might be familiar with an older API where the ref attribute is a string, like "textInput", and the DOM node is accessed as this.refs.textInput. We advise against it because string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases. If you're currently using this.refs.textInput to access refs, we recommend the callback pattern instead.

Instead do:

constructor(props) {
  this.nameInputRef;
  this.descriptionInputRef;
}

...

  <input ref={(el) => {this.nameInputRef = el;} placeholder='Enter the name of the item' />
  <input ref={(el) => {this.descriptionInputRef = el;} placeholder='Enter the description of the item' />

Upvotes: 1

Sulthan
Sulthan

Reputation: 130102

The method is not bound to this when used as a function:

<button onClick={this.handleClick.bind(this)}>Submit</button>

or

<button onClick={event => this.handleClick(event)}>Submit</button>

or bind it in constructor:

constructor(props, context) {
   super(props, context);

   this.handleClick = this.handleClick.bind(this);
}

Upvotes: 8

Related Questions