in

React: Handling Form Submission

Intro

We will continue to work with this simple text input that we are turning into a search bar.

class SearchBar extends React.Component {
  // here we decide what to do with those changes
  state = { term: "" };

  render() {
    return (
      <div className="ui segment">
        <form className="ui form">
          <div className="field">
            <label>Image Search: </label>
            <input
              type="text"
              value={this.state.term}
              onChange={(e) => this.setState({ term: e.target.value })}
            />
          </div>
        </form>
      </div>
    );
  }
}

We have already turned this into a controlled element where the value of the input is now decided by the state of the component, which is updated every time the value of the input is changed.

Default Form Submission Behavior

Currently when the user presses enter on the form the page will reload and behind the scenes, the html form is attempting to send a POST request to the server backend. We don’t have a backend to handle this post request. What we want to do is hijack this default behavior and do something else.

Prevent Default Behaviour

To prevent the default form submission behavior we create a new event handler that intercepts the form submission and that event handler uses the .preventDefault() method.

class SearchBar extends React.Component {
  // here we decide what to do with those changes
  state = { term: "" };

  onFormSubmit(event) {
    event.preventDefault();
  }

  render() {
    return (
      <div className="ui segment">
        <form  onSubmit={this.onFormSubmit} className="ui form">
          <div className="field">
            <label>Image Search: </label>
            <input
              type="text"
              value={this.state.term}
              onChange={(e) => this.setState({ term: e.target.value })}
            />
          </div>
        </form>
      </div>
    );
  }
}

At this point we have not specified what we want to do on submission, we have just intercepted and prevent the default behavior (submitting a post request and reloading the page).

The Most Common Error In React: this is undefined

At this point you would think that we could add the following to the onFormSubmit method

onFormSubmit(event) {
    event.preventDefault();
    console.log(this.state.term);
  }

But if you tried to submit the form now you would get the following error.

We have an issue where this is undefined, because components do not auto-bind methods to themselves. This can be very confusing, there are some good posts about this.

Stack Overflow

Andrew Connel

Or for a more in depth look at the this keyword in general I have a good post here:

In short, we can covert this to an arrow function, because one of the features of arrow functions is that they automatically bind this.

 onFormSubmit = (event) => {
    event.preventDefault();
    console.log(this.state.term);
  }

And now we successfully get the feedback in the console when we submit the input.

Communicating Child to Parent

So far we have worked with props to send information from parent elements to child elements. However now we have the problem of needing to send information from our child element (the search bar component) to it’s parent element (the App component). To do that we will be invoking callbacks.

Invoking Callback

The short explanation is that we define a function in the parent component that describes what we want to do with the input. Then we pass that function into the child component with a prop. So in effect the function is living in the parent app for organizational purposes, but it is being executed inside of the child component. Here is the parent component App

class App extends React.Component {
  onSearchSubmit(input) {
    console.log(input);
  }

  render() {
    return (
      <div className="ui container" style={{ marginTop: "10px" }}>
        <SearchBar onSubmit={this.onSearchSubmit} />
      </div>
    );
  }
}

Note that we have converted the component to a class component. Then we have defined the function onSearchSubmit which is where we are describing what we want to do with the search term. Right now we are just logging it in the console.

This function takes one argument, which is going to be the value of the field when it is submitted.

onSearchSubmit(input) {
    console.log(input);
  }

Then down in the SearchBar component JSX we are creating a prop called onSubmit and passing in our new function.

<SearchBar onSubmit={this.onSearchSubmit} />

Note that inside of the child component we were required to us the name onSubmit or onChange because those were hardcoded methods on html elements. Here we can use any term we want because it is simply a prop on a component. We are still going to use the term onSubmit because it is a good descriptor of when this prop will be invoked.

Then if we go back to our child component, the search bar we can see the following.

class SearchBar extends React.Component {
  
  state = { term: "" };

  onFormSubmit = (event) => {
    event.preventDefault();
    this.props.onSubmit(this.state.term);
  }

  render() {
    return (
      <div className="ui segment">
        <form  onSubmit={this.onFormSubmit} className="ui form">
          <div className="field">
            <label>Image Search: </label>
            <input
              type="text"
              value={this.state.term}
              onChange={(e) => this.setState({ term: e.target.value })}
            />
          </div>
        </form>
      </div>
    );
  }
}

We have added to our onFormSubmit function

this.props.onSubmit(this.state.term);

which is referencing the function we wrote in the parent App component and passed in with a prop, and then submitting as it’s argument the contents of the form, which are tracked with state.term.

And when does this prop function actually get called?

<form  onSubmit={this.onFormSubmit} className="ui form">

onSubmit.

So have we really passed the value to the parent element? I would say no. We have written the functionality in the parent element, and then passed the functionality down to the child, where the argument that the function requires are being stored.

But the effect is basically the same, and we will see this pattern frequently.

The net effect is that the onSearchSubmit function from the parent App component is running when the form is submitted. And because the function is being referenced in the App component, if you check the console, the JS file that is referenced next to the console log is in fact the App.js file. The prop is not copying the function down, it is referencing back up to itself.

React Logo

React: Controlled Vs Uncontrolled Elements

React Logo

React: Working With API’s, Mapping Arrays & Looping Images