How to handle User Inputs with Forms and Events in React.js?

In this tutorial, you’ll learn how to handle user inputs, how to fetch some data from an API (Application Programming Interface) and how to display a list of data in the form of records.

You’re going to build an app that’ll help you search for any picture you want to see. You’ll search for something in a search bar and you’ll get the images result in the same page.

You’re going to build two versions for the same app. In version 1, you’ll get the images one after another (in the form of rows). In version 2, you’ll get the images in a dynamic way such that it covers the entire width of your browser screen and display as many images as possible.

Version 1:

Reactjs List

Version 2:

Reactjs Image List

So, as you might’ve guessed, Version 2 is a bit more complicated than Version 1 because you’ll need to figure out the dynamic sizes of images to be fit in the browser width for all the resultant images. This is more of a CSS work, however you’ll learn a lot about React eventually. You’ll learn about displaying components at dynamic places, getting data from an API request, rendering those data on the browser screen.

And responding to user input and user requests. If that doesn’t sound a lot, the working application at the end of this chapter will give you enough confidence to create any app that deals with user interaction.

Now, let’s create a new project with the following command. Make sure you’re in a directory where you keep all your React projects. For example, I keep mine inside F:\Projects\React.

Now, go to that directory and run the following command:

create-react-app images

You’re going to call this project Images, as it won’t do much but help you find images on the Internet for the searched query and show you the images in the exact same page.

The App component is going to have, at least two more components, named the SearchBar component (at the top) and the ImageList component (right after it). Therefore, the App component will show instances of both SearchBar and the ImageList.

Inside your project folder, when opened inside the editor, delete all the files from the src directory.

Inside src, create a new file called index.js.

Now, add a new folder inside the src directory and call it components.

Inside the components folder, add a new file called App.js with the following code:

import React from 'react';

const App = () => {
    return <div>App Component</div>;
}

export default App;

Now, come back to index.js file and write the following code:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

ReactDOM.render(
   <App />,
   document.querySelector("#root")
);

In the third line of the above code, you’re basically importing the App component from inside the components directory.

Save the files, run the server with npm start command and you should see “App Component” at localhost:3000.

How to show forms to the users?

Now, create a new file named SearchBar.js inside the components directory and write the following code:

import React from 'react';

class SearchBar extends React.Component {
    render() {
        return(
            <div>Search Bar</div>
        );
    }
}

export default SearchBar;

Inside the App.js file, import SearchBar and show it inside the App component:

import React from 'react';
import SearchBar from './SearchBar';

const App = () => {
    return <div><SearchBar /></div>;
}

export default App;

Save the files once again, and you should see “Search Bar” written on the screen.

Now, it’s time to show the search form inside the SearchBar.js component.

First of all, open index.html from the public folder and add the following CDN in the head:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css" />

Next, come back to SearchBar.js and create a form as follows:

import React from 'react';

class SearchBar extends React.Component {
    render() {
        return(
            <div className="ui segment">
                <form className="ui form">
                    <div className="field">
                        <label>Image Search</label>
                        <input type="text"/>
                    </div>
                </form>    
            </div>
        );
    }
}

export default SearchBar;

Next, go back to App.js and make the following changes to make the form fit better with a bit of top margin spacing:

import React from 'react';
import SearchBar from './SearchBar';

const App = () => {
    return(
        <div className="ui container" style={{ marginTop: '10px'}}>
            <SearchBar />
        </div>
    );
}


export default App;

Create SearchBar Component

Now, create a new file named SearchBar.js inside the components directory and write the following code:

import React from 'react';

class SearchBar extends React.Component {
    render() {
        return(
            <div>Search Bar</div>
        );
    }
}

export default SearchBar;

Inside the App.js file, import SearchBar and show it inside the App component:

import React from 'react';
import SearchBar from './SearchBar';

const App = () => {
    return <div><SearchBar /></div>;
}

export default App;

Save the files once again, and you should see “Search Bar” written on the screen.

Now, it’s time to show the search form inside the SearchBar.js component.

First of all, open index.html from the public folder and add the following CDN in the head:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css" />

Next, come back to SearchBar.js and create a form as follows:

import React from 'react';

class SearchBar extends React.Component {
    render() {
        return(
            <div className="ui segment">
                <form className="ui form">
                    <div className="field">
                        <label>Image Search</label>
                        <input type="text"/>
                    </div>
                </form>    
            </div>
        );
    }
}

export default SearchBar;

Next, go back to App.js and make the following changes to make the form fit better with a bit of top margin spacing:

import React from 'react';
import SearchBar from './SearchBar';

const App = () => {
    return(
        <div className="ui container" style={{ marginTop: '10px'}}>
            <SearchBar />
        </div>
    );
}

export default App;

How to create Event Handlers?

Now you want to make sure that you get notified every time user types something in the search bar. For example, here the input is “some text”:

Reactjs Searchbar

You’ll need to add a new prop to the input field called onChange and you’ll have to pass a reference to the onInputChange method that you separately create. However, you do not use onInputChange() when assigning it to onChange prop. Instead you just write onInputChange. This is because you don’t want the method to be immediately invoked but in a later point in time. onInputChange takes in a parameter called event, which you can use to access several objects.

Right now, you only want to console.log the key strokes as typed by the user. So, if you save the below file, open your web browser, open the console window and type something in the search input, you should see the typed text in the console window.

To get started, make the following changes in the SearchBar.js file:

import React from 'react';


class SearchBar extends React.Component {

    onInputChange(event) {

        console.log(event.target.value);

    }


    render() {
        return(
            <div className="ui segment">
                <form className="ui form">
                    <div className="field">
                        <label>Image Search</label>
                        <input type="text" onChange={this.onInputChange} />
                    </div>
                </form>    
            </div>
        );
    }
}

export default SearchBar;

It’s worth notifying that you can call onInputChange method whatever you want. It is a user defined method. However, onChange is a reserved method and can’t have a different name for the same purpose.

There’s one more way of doing the same thing. Instead of calling onInputChange from the input field, you can define the function there itself and remove onInputChange method altogether:

<input type="text" onChange={(event) => console.log(event.target.value)} />

You can further shorten the code like this, and you’ll see similar code a lot in many documentations and tutorials:

<input type="text" onChange={e => console.log(e.target.value)} />

For now, let’s revert it back and keep the onInputChange method.

Controlled vs uncontrolled form element

Right now, the form you have is called an uncontrolled form element. This is because whatever keys you’re pressing, whatever data is being entered to the search input, only stays inside the DOM. There is no way for React, to access the entered data. However, with the help of states, React can keep a track of those data and use it as necessary.

Therefore, you’re going to store entered text in a property called term inside the state object. You’ll update this property whenever there’s a change in the input text search field, thus assigning the method to onChange prop. Finally, copy the value from this.state.term to the input text value (getting replaced each time). SearchBar.js should now look like:

import React from 'react';

class SearchBar extends React.Component {
    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>
        );
    }
}

export default SearchBar;

How to handle form submission / submit?

Right now, if you enter some text in the search input box and press the Enter key, the browser just refreshes itself and everything goes away. There should be a way to handle the form submission so that Enter key doesn’t refresh the page. And of course, there is.

You have to create a new method, let’s call it onFormSubmit, that takes in event as a parameter and you can use event.preventDefault() to prevent the default behavior of pressing the Enter key (refresh the page). You’ll need to assign this method to the form field.

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

And define the method right before the render method:

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

You’ll notice that when you press the Enter key, the method is invoked and you’ll see the following error:

TypeError: this is undefined

Or

TypeError: Cannot read property ‘state’ of undefined

This is basically because React thinks state belongs to undefined since it cannot read the “this” instance inside the SearchBar class. There are a couple of ways to resolve the issue.

Solution 1:

You can convert the onFormSubmit method into an arrow function and the error should go away:

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

This is because arrow functions understand this operator and takes it as an instance of the class the function is immediately defined inside. That is, the value of this is equal to the SearchBar instance.

Solution 2:

At the form field, change this.onFormSubmit into an arrow function as follows:

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

So, choose whichever solution seems more suitable to you.

How to pass data from child to parent component?

Now that you’ve successfully got a way to access user input by the SearchBar component, you need to pass the data (search term) back to the App component. However, App is the parent component which has the SearchBar component as the child component. And props can only be passed from the parent to the child component.

There is a trick to get data back from a child component. You’re going to define a function inside the parent component (called the App component) which will be passed to the child component as a prop. Later, this function will be called inside the child component (SearchBar) and the value will be passed to the function.

Before doing that, you need to convert the App component from a functional component to a class based component (App.js). Next, you’ll create a function called onSearchSubmit which will take a parameter called term, in the App component. Pass this function to the SearchBar component as a prop called onSubmit. App.js should look like:

import React from 'react';
import SearchBar from './SearchBar';

class App extends React.Component {

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

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

export default App;

Next, inside the SearchBar component (SearchBar.js), pass the value (this.state.term) to the onSubmit() function:

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

You’ll notice that you’re using this.props instead of just props. It is because this is how you access props in class based components.

Now, if you save the files and run the server, you should see the entered text from the App component:

As in this example, I typed “cindy kabiraj” and hit the Enter key. In the console window, I can clearly see that the console output is from App.js file (line number 7):

 

Leave a Comment