2

I'm creating an simple React app and I know I should use state for this case, but I found an example doing a form like this and I decided to try. Now I don't know why this doesn't work and I would like to understand the reason I'm receiving this message. I've searched a lot and all the cases with a similar error seem kind of specific. I'm receiving this error message:

Error in /~/src/Form.js (14:26)
Cannot read property 'userNameInput' of undefined

this is my code: App.js:

import React from 'react';
import './style.css';
import CardList from './CardList';
import Form from './Form';

const testData = [
  {
    name: 'Dan Abramov',
    avatar_url: 'https://avatars0.githubusercontent.com/u/810438?v=4',
    company: '@facebook'
  },
  {
    name: 'Sophie Alpert',
    avatar_url: 'https://avatars2.githubusercontent.com/u/6820?v=4',
    company: 'Humu'
  },
  {
    name: 'Sebastian Markbåge',
    avatar_url: 'https://avatars2.githubusercontent.com/u/63648?v=4',
    company: 'Facebook'
  }
];

class App extends React.Component {
  render() {
    return (
      <div>
        <div className="header">{this.props.title}</div>
        <Form />
        <CardList profiles={testData} />
      </div>
    );
  }
}

export default App;

Card.js:

import React from 'react';

class Card extends React.Component {
  render() {
    const profile = this.props;
    return (
      <div className="github-profile">
        <img src={profile.avatar_url} alt="profile-img" />
        <div className="info">
          <div className="name">{profile.name}</div>
          <div className="company">{profile.company}</div>
        </div>
      </div>
    );
  }
}

export default Card;

CardList.js:

import React from 'react';

import Card from './Card';

const CardList = props => {
  return props.profiles.map(profile => <Card {...profile} />);
};

export default CardList;

Form.js:

import React from 'react';

class Form extends React.Component {
  userNameInput = {};

  handleSubmit(event) {
    event.preventDefault();
    console.log(this.userNameInput.current.value);
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type="text"
          placeholder="Github Username"
          // name="username"
          ref={this.userNameInput}
          required
        />
        <button>Add Card</button>
      </form>
    );
  }
}

export default Form;

index.js:

import React from 'react';
import ReactDOM from 'react-dom';

import App from './App';

ReactDOM.render(
  <App title="Github Cards App" />,
  document.getElementById('root')
);

Can you please explain why this kind of error occurs so I'll know better how to deal with in the next time?

rmlockerd
  • 3,776
  • 2
  • 15
  • 25
  • Does this answer your question? [Value of this in React event handler](https://stackoverflow.com/questions/29732015/value-of-this-in-react-event-handler) – ggorlen Aug 06 '21 at 19:33

2 Answers2

2

You have to bind the handleSubmit function. Do this by writing this in top of the Form component:

handleSubmit = this.handleSubmit.bind(this);

You can read this to know why you need to bind the function: why do you need to bind a function in a constructor

I also noticed a warning when reproducing the error:

Warning: Unexpected ref object provided for input. Use either a ref-setter function or React.createRef()

You can fix this by writing:

userNameInput = React.createRef();

instead of:

userNameInput = {};
1

It's the <form onSubmit={this.handleSubmit}> part of your code.

When onSubmit triggers, it will call the handleSubmit method but with this set to (as far as I know) the event object, but definitely not your component. Use an arrow function intead:

<form onSubmit={e => this.handleSubmit(e)}>

This will make sure handleSubmit is called with the correct this.

Kelvin Schoofs
  • 8,323
  • 1
  • 12
  • 31
  • `this` is set to `undefined`, as a regular strict-mode unbound call (that's why it triggers an error on `.userNameInput` and not on `.current`), but otherwise you're right. +1 – FZs Aug 06 '21 at 20:14