Sean Barker
Sean Barker

Reputation: 351

Value of this is undefined

I have a this value inside an if statement, nested inside a my handleFormChange function. I've tried to use arrow functions with this function to bind the value of this but im getting the following error message:

TypeError: Cannot set property 'author' of undefined

From my understanding usually you find the this value by looking at where the function containing this is called. However, in my case im struggling to work this out. Can anyone explain to me why it is undefined and how to solve this issue? Here is the code:

class CommentForm extends React.Component{

    constructor(props){
        super(props)


        var comment={author:'', message:''}
    }


    handleSubmit= (e)=>{
        e.preventDefault()
        var authorVal = this.comment.author;
        var textVal = this.comment.message;
        //this stops any comment submittal if anything missing
        if (!textVal || !authorVal) {
         return;
        }
        this.props.onCommentSubmit(this.comment);
        //reset form values
        e.target[0].value = '';
        e.target[1].value = '';
        return;
    }


    handleFormChange= (e)=>{
        e.preventDefault()
        if(e.target.name==='author'){
            var author = e.target.value.trim();
            this.comment.author = author
        }else if(e.target.name==='message'){
            var message = e.target.value.trim();
            this.comment.message = message
        }
    }

    render() {
    return (

        <form className = "ui form" method="post" onChange={(e)=>{this.handleFormChange(e)}} onSubmit={(e)=>{this.handleSubmit(e)}}>
          <div className="form-group">
            <input
              className="form-control"
              placeholder="user..."
              name="author"
              type="text"
            />
          </div>

          <div className="form-group">
            <textarea
              className="form-control"
              placeholder="comment..."
              name="message"        
            />
          </div>



          <div className="form-group">
            <button disabled={null} className="btn btn-primary">
              Comment &#10148;
            </button>
          </div>
        </form>

    );
  }
}

export default CommentForm

Upvotes: 0

Views: 153

Answers (2)

Fiodorov Andrei
Fiodorov Andrei

Reputation: 2018

I decided to write even if you proposed the correct answer for the simple reason that I think my code is closer to what it published.

import React, { Component } from "react";
import ReactDOM from "react-dom";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      comment: {},
      some: 1
    };
  }

  handleFormChange = e => {
    e.preventDefault();
    let { comment } = this.state;
    const newCommentState = function() {
      let returnObj = { ...comment };
      returnObj[this.target.name] = this.target.value.trim();
      return returnObj;
    }.bind(e)();
    this.setState({ comment: newCommentState });
  };

  handleSubmit = e => {
    e.preventDefault();
    let { comment } = this.state;
    if (!comment.author || !comment.message) return;

    this.props.onCommentSubmit(comment);
    this.setState({ comment: {} });
    e.target[0].value = "";
    e.target[1].value = "";
  };

  render() {
    return (
      <div>
        <form
          className="ui form"
          method="post"
          onChange={e => {
            this.handleFormChange(e);
          }}
          onSubmit={e => {
            this.handleSubmit(e);
          }}
        >
          <div className="form-group">
            <input
              className="form-control"
              placeholder="user..."
              name="author"
              type="text"
            />
          </div>

          <div className="form-group">
            <textarea
              className="form-control"
              placeholder="comment..."
              name="message"
            />
          </div>

          <div className="form-group">
            <button disabled={null} className="btn btn-primary">
              Comment &#10148;
            </button>
          </div>
        </form>
      </div>
    );
  }
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Live example:

Edit patient-bush-27cp5

Upvotes: 0

Yuan-Hao Chiang
Yuan-Hao Chiang

Reputation: 2603

The first step into learning how to do what you want is to study how React's State works (official docs are great at explaning it).

This example is not complete, but should guide you through the proccess.

class CommentForm extends Component {

constructor(props) {
  super(props);

  this.state = {
    author  : '',
    message : '',
  }

  this.onChangeAuthorName = this.onChangeAuthorName.bind(this);
  this.onBlurAuthorName   = this.onBlurAuthorName.bind(this);
}

onChangeAuthorName(e) {
  this.setState({ author: e.target.value });
}

onBlurAuthorName() {
  // trim on blur (or when you send to the network, to avoid
  // having the user not being able to add empty whitespaces
  // while typing
  this.setState({ author: this.state.author.trim() })
}

render() {
  return (
    ...
    <input value={this.state.author} onChange={this.onChangeAuthorName} onBlur={this.onBlurAuthorName} />
    ...
  );
}

}

Usually, when you want to "set" variables in React, you don't add them as you do to in Javascript classes (this.comment = e.target.value), but instead, use the function setState(). From the docs:

// Wrong
this.state.comment = 'Hello';

Instead, use setState():

// Correct
this.setState({comment: 'Hello'});

(NOTE: Alternatively, this could be done using React Hooks, but I recommend you learn the lifecycle methods firsthand. Good luck!)

Upvotes: 3

Related Questions