Understanding how React handles input state: A deep dive
Tags: react, webdev
Published: 2023-09-05 19:50:53

**Written by [Abhinav Anshul](https://blog.logrocket.com/author/abhinavanshul/)✏️**

Today’s web applications are more interactive, user-centric, and data-heavy than ever. Therefore, handling input fields, forms, and other such elements is a crucial aspect of creating and managing dynamic web pages. These elements are simply native input elements used for data manipulation and interaction. In the context of React, “input state” refers to the current state of input elements, including input tags, checkboxes, radio buttons, and other such native form elements. 

This article delves into how React manages input states and explores various strategies for handling state changes. You will also learn how React leverages the concept of controlled and uncontrolled components to [improve React app performance](https://blog.logrocket.com/optimizing-performance-react-app/#:~:text=We%20can%20use%20Reselect%2C%20a,recalculate%20if%20the%20value%20changes.) and reduce re-rendering. 

Jump ahead:

*   [Understanding controlled and uncontrolled components](#understanding-controlled-uncontrolled-components)
    *   [What are controlled components?](#what-controlled-components)
    *   [What are uncontrolled components?](#what-uncontrolled-components)
*   [Exploring input state with `onFocus` and `onBlur` events](#exploring-input-state-onfocus-onblur-events-react)
    *   [Understanding how `onFocus` events work with input elements](#understanding-onfocus-events-input-elements)
    *   [Understanding how `onBlur` events work with input elements](#understanding-onblur-events-input-elements)
*   [Leveraging third-party libraries to handle input state in React](#leveraging-third-party-libraries-handle-input-state-react)

You can [check out the CodeSandbox demo](https://codesandbox.io/s/onfocus-onblur-tvzkjn) we’ll use to explore how `onFocus` and `onBlur` events work with input elements. But first, let’s dive into understanding the difference between controlled and uncontrolled components.

## Understanding controlled and uncontrolled components <a name="understanding-controlled-uncontrolled-components">

Native HMTL input elements like `input`, `select`, and others maintain their own state and mutate it whenever the user types in them. However, this isn’t the case with React. 

Instead, React keeps the input state in the component itself, passing it down to the `input` element and mutating the stored state using the `setter` function pattern. This `setter` function is usually a lazy callback function such as [the `useState` Hook](https://blog.logrocket.com/guide-usestate-react/), which is widely used for mutating and managing input states. 

With that in mind, let’s dive into the differences between controlled and uncontrolled components in React.

### What are controlled components? <a name="what-controlled-components">

If you define the component state as the single source of truth, and data flows from the parent component to the element, we call it a controlled component. You usually need to store your state somewhere before it passes down to the element. 

Controlled components are typically easier to debug, and the React team recommends this approach in most use cases. In the example below, the "single source of truth" is the `name` state. This `name` state is initialized using the `useState` Hook, then passed down and set as a value to the `input` element:

```javascript
import { useState } from 'react'

function App(){
const [name, setName] = useState("");
return(
<div>
<h1>Controlled Component</h1>
<label>Name :</label>
<input name="name" type="text" value={name} onChange={(e) => setName(e.target.value)}
/>
</div>
)
}
```

This approach ensures that you maintain the state in the component itself, but outside the element. You can even use the same state to render it on the UI, which is not possible with an uncontrolled component.

### What are uncontrolled components? <a name="what-uncontrolled-components">

An [alternative to the controlled component](https://blog.logrocket.com/controlled-vs-uncontrolled-components-in-react/) is the uncontrolled component, where the state is managed by the component's internal state. An uncontrolled component updates its state based on user manipulation. 

In many use cases, an uncontrolled component is generally an [anti-pattern and not the recommended approach](https://blog.logrocket.com/complete-guide-react-refs/#avoid-anti-pattern). However, if you need to keep the "source of truth" in the DOM itself without relying on Hooks to manage the state, this can be a good option. 

An uncontrolled component can also be useful for quick UI prototyping and porting HTML code to a React codebase. 

In the example below, `input` is an uncontrolled component. You can access its value using the `ref` property:

```javascript
import { useRef } from 'react'

function App(){
const inputRef = useRef(null)
useEffect(() => {
//log what the user types in
console.log(inputRef.current.value)
},[inputRef.current.value])

return(
<div>
<h1>Uncontrolled Component</h1>
  <label>Name :</label>
<input name="name" ref={inputRef} type="text" />
</div>
)
}
```

The `useEffect` Hook written above simply logs the currently typed value. To send your input data to an actual API, you can use the `onSubmit` attribute:

```javascript
import { useRef } from 'react'

function App(){
const inputRef = useRef(null)
const handleSubmit = () => {
console.log(inputRef.current.value)
}

return(
<form onSubmit={handleSubmit}>
<h1>Uncontrolled Component</h1>
  <label>Name :</label>
<input name="name" ref={inputRef} type="text" />
</form>
)
}
```

The `onSubmit` attribute fires only when the form is submitted, whereas the `onChange` attribute fires at each keystroke — in other words, every time the data is manipulated. 

Generally, you should opt for the controlled component pattern, which makes it easier to maintain states. States paired with the `useState` Hook make controlled components quite robust and maintainable, and this approach introduces fewer bugs compared to uncontrolled components. 

Most importantly, do not mix and match both patterns at once in a form. If you are using a controlled component, follow it consistently throughout your form. Otherwise, React will give you a warning.

## Exploring input state with `onFocus` and `onBlur` events in React <a name="exploring-input-state-onfocus-onblur-events-react">

You have seen how `onChange` and `onSubmit` work both in controlled and uncontrolled component patterns. There are various other native HTML form attributes and events that make managing input cases easier. Let’s explore two types: `onFocus` and `onBlur` events.

### Understanding how `onFocus` events work with input elements <a name="understanding-onfocus-events-input-elements">

`onFocus` is a native HTML event that triggers only when the target element is in focus. You can leverage this event to build UI interactions such as changing outline colors, providing tooltip feedback to the users, minor animations and interactions, and more. 

In the example below, the UI should ideally render `Focused` whenever the `input` element is in focus and `Not Focused` whenever the `input` element is not in focus:

```javascript
import { useState } from "react";

export default function App() {
  const [text, setText] = useState("");
  const [isFocus, setFocus] = useState(false);

  const handleFocus = () => {
    setFocus(true);
  };

  return (
    <div className="App">
      <input
        type="text"
        value={text}
        onFocus={handleFocus}
        onChange={(e) => setText(e.target.value)}
      />
      <div>{isFocus ? "Focused" : "Not Focused"}</div>
    </div>
  );
}
```

However, when this code is put into action, you might notice the text does not display `Not Focused` as we want it to when the `input` is not in focus. This is where the missing event attribute called `onBlur` comes into play.

### Understanding how `onBlur` events work with input elements <a name="understanding-onblur-events-input-elements">

`onBlur` works as a counterpart to `onFocus` events — it gets triggered when an element goes out of focus. You can pair these two event attributes together to track when an element is in focus and when it goes out of focus. 

If you go back to the code above and add `onBlur`, the code will work as expected. In the example below, the two event attributes are working together to track the `input` element’s state — specifically, whether the element is in focus or not:

```javascript
import { useState } from "react";

export default function App() {
  const [text, setText] = useState("");
  const [isFocus, setFocus] = useState(false);

  const handleFocus = () => {
    setFocus(true);
  };

  const handleBlur = () => {
    setFocus(false);
  };

  return (
    <div className="App">
      <input
        type="text"
        value={text}
        onFocus={handleFocus}
        onBlur={handleBlur}
        onChange={(e) => setText(e.target.value)}
      />
      <div>{isFocus ? "Focus" : "Not Focus"}</div>
    </div>
  );
}
```

Native JavaScript events such as `onBlur` and `onFocus` help when building forms or even simple input states. These events get triggered when users interact with input elements, providing visual feedback to guide the user: ![Text Box Input Element Shown With Text Underneath Reading Not Focus. User Clicks Into Text Box, Changing Text Underneath Automatically To Read Focus Instead. User Then Clicks Outside Of Text Box Again, Returning Text Underneath To Read Not Focus Again.](http://blog.logrocket.com/wp-content/uploads/2023/08/Demonstrating-onFocus-onBlur-events.gif) 

Providing visual feedback in this way can help in many situations — for example, if there are any issues with the data entered or other such formatting problems in the form. 

Building out such interactions takes time and plenty of effort. If you are new to forms, make sure you understand how these interactions work natively before jumping to third-party solutions. 

However, if you’re working on apps professionally that are intended for organizational or commercial use, it’s a much better idea to opt for third-party packages and leverage their APIs. This will save time and ensure you’re using production-ready solutions. 

You can play around with the [code example above on Code Sandbox](https://codesandbox.io/s/onfocus-onblur-tvzkjn) to try out different ideas for using these native events in your React app.

## Leveraging third-party libraries to handle input state in React <a name="leveraging-third-party-libraries-handle-input-state-react">

As I mentioned before, instead of reinventing the wheel, it’s best to utilize an already-built, production-ready form and input management solution for more complex data handling. 

[Popular libraries such as React Hook Form](https://blog.logrocket.com/react-hook-form-complete-guide/), Formik, and React Final Form are very efficient when it comes to managing complex use cases. 

Established form handling libraries typically provide high-level APIs for error handling and pattern matching. They are also usually unstyled, so you can easily pair them with your favorite component library. 

Let’s see an example of a form built with Formik:

```javascript
import React from "react";
import { Formik } from "formik";
import "./styles.css";
const LoginForm = () => (
  <div className="login-container">
    <Formik
      initialValues={{ email: "", password: "" }}
      validate={(values) => {
        const errors = {};
        if (!values.email) {
          errors.email = "Email cannot be empty";
        } else if (
          !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
        ) {
          errors.email = "Oops! Email address is invalid";
        }
        return errors;
      }}
      onSubmit={(values, { setSubmitting }) => {
        // Send values to an API here
        console.log("email sent");
      }}
    >
      {({
        values,
        errors,
        touched,
        handleChange,
        handleBlur,
        handleSubmit,
        isSubmitting
        /* and other goodies */
      }) => (
        <form onSubmit={handleSubmit}>
          <input
            placeholder="email"
            type="email"
            name="email"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.email}
          />
          <br />
          {errors.email && touched.email && errors.email}
          <br />
          <input
            placeholder="password"
            type="password"
            name="password"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.password}
          />
          {errors.password && touched.password && errors.password}
          <br />
          <button type="submit" disabled={isSubmitting}>
            Submit
          </button>
        </form>
      )}
    </Formik>
  </div>
);
export default LoginForm;
```

As you can see, by doing the bare minimum, Formik removes the pain points of complex input data handling scenarios, such as error handling, warning, and pattern checking. For exampe:

*   You have high-level APIs to manage custom error messages
*   You can trigger texts when fields are being touched using a cursor
*   You can format data before sending it to the backend API

Check out the result of our Formik form below: ![Simple Black And White Form With Two Filled In Text Box Input Elements And A Submit Button. Text Underneath Text Box For User Email Informs User That Email Address Is Invalid](http://blog.logrocket.com/wp-content/uploads/2023/08/Formik-form-demonstrating-input-state-management.png) All the other libraries out there — such as [React Hook Form](https://blog.logrocket.com/react-hook-form-complete-guide/) and [React Final Form](https://blog.logrocket.com/build-high-performance-forms-using-react-final-form/) — more or less follow a similar pattern. This allows you to focus more on the actual logic rather than building forms over and over again. 

If you are building a form with many moving parts that requires extensive data manipulation, using a third-party library such as [Formik to build forms and manage input states](https://blog.logrocket.com/building-forms-formik-react/) can be a very good idea.

## Conclusion

Handing input states in React can be cumbersome at times. But with the right approach, following standards such as using controlled components, React makes it easier to handle data. 

If your project is small to mid-level and form-intensive, it may be better to skip libraries and handle input states on your own. However, for a more form-intensive consumer product, it’s usually better to opt for a third-party form library. 

React alleviates the challenges that come with input handling, providing events such as `onFocus`, `onBlur`, and more to make building and managing forms and data easier. Especially when pairing React with a library, building forms can be very scalable and easy to debug.

---
## Get set up with LogRocket's modern React error tracking in minutes:

1. Visit https://logrocket.com/signup/ to get an app ID.
2. Install LogRocket via NPM or script tag. `LogRocket.init()` must be called client-side, not server-side.

NPM:
```bash
$ npm i --save logrocket 

// Code:

import LogRocket from 'logrocket'; 
LogRocket.init('app/id');
```
Script Tag:
```javascript
Add to your HTML:

<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
```

3.(Optional) Install plugins for deeper integrations with your stack:
*   Redux middleware
*   ngrx middleware
*   Vuex plugin

[Get started now](https://lp.logrocket.com/blg/signup)