Handling inputs in React

To build interactive web applications, you need user interactions, and by extension, forms for users to interact with. You see forms everywhere – from simple input fields to checkboxes and select dropdowns that allow users to choose one of the few provided options.

If you want to build interactive apps in React, then you need a different approach. React does not allow you to access DOM elements, but provides a different (and arguably better) way to handle user inputs in React.

The focus of this article is to explore how to create and manage forms to implement dynamic features. For example, you can dynamically validate user input values. Let’s explore how to create and manage various types of inputs. Finally, we’re also going to discuss the idea of controlled components, why its necessary, and how React developers use it in practice.

Basic forms in React

If you know how to create a form in HTML, you can create one in React. JSX is a templating language that allows you to structure web applications using the same syntax as HTML.

Every React components needs to return JSX that describes structure of the component. If you want to return an input field, all you need is to include a <input /> element the same way you do in HTML. Let’s look at an example:

function App() {

return (<input type=”text”></input>)

}

That’s it. A JavaScript component that returns HTML. It may look strange, but JSX facilitates development with React. Without it, you’d have to make calls to createElement() top-level API in React.

React does have one rule when it comes to JSX – all components must return only one element. If there are multiple elements, they must be wrapped with another element. A simple <div> will do the trick.

A simple controlled input

React is a JavaScript library that is designed to ‘react’ to latest changes in the app. It uses state to do that. Every component can have a state object to store latest changes in the app. User inputs are constantly changing, so it’s a good practice to store them in the state.

Inputs that get their value from the state, and in turn update the state whenever there’s a change to value in the field, are called controlled inputs.

You can easily set a handleChange event handler on the input from example above. You will also need to set its value attribute to a value from the state.

You can easily initialize state in class components. You will need a useState hook to do that in functional components. In a way, useState simplifies the syntax for creating as well as updating the state. I personally use it all the time.

The code for better, more robust controlled input would look something like this:

function App() {

const [name, setName] = useState(“”)

return (<input type=”text” value={name} onChange={(e)=>setName(e.target.value)}></input>)

}

The code got a bit more complex, but storing inputs in the state increases consistency of the app. Plus you always know current value in the input field. You can use that to dynamically validate current inputs or even output input on the screen.

You don't need to use this type of input or even change event. You can even listen for specific keys that are pressed down. This article explores onkeydown enter in React.

Note that you need to define two variables – name and setName to store two values returned by the useState hook. First variable stores the state value itself. The second variable is supposed to store the function to update the variable. This syntax makes it easy to use state values in practice. A separate function to update the state also facilitates event handling.

In the JSX, you need to use curly braces to set input values to a state variable. You need the same approach to set an inline event handler for change events. So the state is automatically updated every time users or deletes something from the input field.

Finally, we pass e.target.value as argument to the onChange event handler. In this case, e is a shorthand for SyntheticEvent. Every event handler receives the object that contains information about the event and input element that triggered it.

Advanced case – form and multiple input fields

Most of the time your forms will be more complex than a single input field. There may be multiple input fields, dropdowns, checkboxes, and so on. You will need to maintain current value of all these inputs. Using the <form> element will also allow you to handle the submit event. Maybe you will want to reset the input fields to default after the form is submitted.

You need to start by creating a <form> element that will wrap around all inputs. You can set onSubmit event handler to handle the submit event and do something (post to the API, or reset fields, or both) when the form is submitted.

When working with multiple fields, you will also need multiple state values. You can use the useState to define them the same way as before. Keep in mind that the argument to the useState() hook will be default value of the variable.

Keep in mind that your form will also need a button with the type of ‘submit’. A normal button won’t do, because clicking it will trigger a ‘click’ event. You want to trigger a submit event instead.

Whenever submit event happens, web apps usually automatically refresh the page. This is the default behavior from old days of internet. But since React apps are rendered on one page (hence why they’re called single page applications), you don’t need to reload. Instead, you can use preventDefault() method on SyntheticEvent instance to stop the page from reloading.

You can do more than that when handling a submit event. A common feature is to clear all input fields. This is easy to do if your form already stores input field values in the state. You only need to use updater functions to reset these values to a default (usually an empty string).

You can even pass an event handler via props. In child component, you will be able to use function from another component in React. This allows you to pass data from child to parents, which is often useful when dealing with complex component trees.