Controlled vs. Uncontrolled Components in React.js

In React.js, form handling is a crucial part of building interactive and dynamic web applications. When dealing with forms, there are two main approaches to managing the form data: Controlled Components and Uncontrolled Components. Understanding the differences between these two approaches is essential for managing state and achieving the desired user experience in your React applications.

What Are Controlled Components?

Controlled components in React are those whose form data is controlled by React’s state. In other words, the value of the input elements (such as text inputs, checkboxes, etc.) is managed by the React component’s state. Any updates to the form input must go through the component’s state, and the React component has full control over the form elements.

Characteristics of Controlled Components

  • Input data is managed in the component’s state.
  • Updates to the input happen via React’s setState (or hooks like useState).
  • The value of the input is always in sync with the component’s state.

Basic Example of Controlled Component

Let’s build a simple controlled component where a user types into an input field, and the text they type is stored and displayed in the component’s state.

				
					import React, { useState } from 'react';

const ControlledComponent = () => {
    const [value, setValue] = useState('');

    const handleChange = (event) => {
        setValue(event.target.value);
    };

    return (
        <div>
            <input type="text" value={value} onChange={handleChange} />
            <p>The current input is: {value}</p>
        </div>
    );
};

export default ControlledComponent;

				
			

Explanation of Controlled Component Example

  • State Management: The useState hook is used to define the value state and the setValue function that updates it.
  • Two-Way Binding: The value prop of the <input> element is bound to the state (value), meaning the input field always reflects the state’s value. When the user types something, the onChange handler updates the state, and the input field rerenders with the updated state.
  • Output: When the user types into the input field, the text they enter is immediately stored in the state and reflected in the paragraph below.

Output of Controlled Component

When the user types in “Hello” into the input field, the displayed text below the input box updates in real-time to:

				
					The current input is: Hello
				
			

What Are Uncontrolled Components?

Uncontrolled components in React manage their own state internally via the DOM, rather than using React’s state. With uncontrolled components, you don’t bind the form input’s value to the component state. Instead, you access the current value of the form input using refs when needed.

Characteristics of Uncontrolled Components

  • Input data is managed directly by the DOM.
  • React doesn’t have control over the form’s value during typing.
  • Refs are used to access the form values when needed.

Basic Example of Uncontrolled Component

Now, let’s build an uncontrolled component where a user types into an input field, but the input value is retrieved using refs instead of managing it via state.

				
					import React, { useRef } from 'react';

const UncontrolledComponent = () => {
    const inputRef = useRef(null);

    const handleSubmit = (event) => {
        event.preventDefault();
        alert(`Input value: ${inputRef.current.value}`);
    };

    return (
        <form onSubmit={handleSubmit}>
            <input type="text" ref={inputRef} />
            <button type="submit">Submit</button>
        </form>
    );
};

export default UncontrolledComponent;

				
			

Explanation of Uncontrolled Component Example

  • Using Refs: We use the useRef hook to create a reference (inputRef) to the input element. This reference allows us to access the input value without relying on React’s state.
  • Accessing Input Value: When the form is submitted, we access the value of the input field using inputRef.current.value.
  • No State Management: Unlike controlled components, we don’t use useState to manage the input’s value. The input manages its value internally through the DOM.

Output of Uncontrolled Component

When the user submits the form, an alert will pop up showing the current input value (e.g., “Hello”).

Differences Between Controlled and Uncontrolled Components

FeatureControlled ComponentsUncontrolled Components
State ManagementManaged by React's state (useState, setState)Managed by the DOM itself using refs
Form Input ControlInput value is controlled by the component’s stateInput value is controlled by the DOM
Two-Way Data BindingYes (input value always reflects the state)No (input value does not automatically sync with the state)
When to Access Input DataIn real-time during input changeWhen necessary, e.g., on form submission
UsageUseful when you need real-time validation or control over form inputsUseful when you don't need real-time control, and accessing data on demand is sufficient

Advanced Example: Form Validation with Controlled Components

Controlled components give you more control over form input, making them perfect for form validation. Let’s see how we can use controlled components to perform basic validation on a form.

Example: Controlled Form with Validation

				
					import React, { useState } from 'react';

const ControlledForm = () => {
    const [email, setEmail] = useState('');
    const [error, setError] = useState('');

    const handleChange = (event) => {
        setEmail(event.target.value);

        // Simple email validation
        if (!event.target.value.includes('@')) {
            setError('Please enter a valid email.');
        } else {
            setError('');
        }
    };

    const handleSubmit = (event) => {
        event.preventDefault();
        if (!error) {
            alert(`Email submitted: ${email}`);
        } else {
            alert('Form contains errors.');
        }
    };

    return (
        <form onSubmit={handleSubmit}>
            <input type="email" value={email} onChange={handleChange} />
            {error && <p style={{ color: 'red' }}>{error}</p>}
            <button type="submit" disabled={error}>Submit</button>
        </form>
    );
};

export default ControlledForm;

				
			

Explanation of Controlled Form with Validation

  • Real-Time Validation: The handleChange function checks if the input value contains an “@” symbol. If it doesn’t, it sets an error message in the state.
  • Disabling Submit: The submit button is disabled if there is an error, ensuring users can only submit valid data.
  • Output: If the user tries to submit an invalid email (without “@”), an error message is shown, and the form cannot be submitted.

Output of Controlled Form

When the user types an invalid email (e.g., “test”), the error message “Please enter a valid email.” appears, and the submit button is disabled.

Advanced Example: Uncontrolled Component with Form Submission

Let’s see how we can handle form submissions using uncontrolled components, where the input values are retrieved only when needed.

Example: Uncontrolled Form with Multiple Inputs

				
					import React, { useRef } from 'react';

const UncontrolledForm = () => {
    const emailRef = useRef(null);
    const passwordRef = useRef(null);

    const handleSubmit = (event) => {
        event.preventDefault();
        const email = emailRef.current.value;
        const password = passwordRef.current.value;

        if (email && password) {
            alert(`Email: ${email}, Password: ${password}`);
        } else {
            alert('Please fill out both fields.');
        }
    };

    return (
        <form onSubmit={handleSubmit}>
            <input type="email" ref={emailRef} placeholder="Email" />
            <input type="password" ref={passwordRef} placeholder="Password" />
            <button type="submit">Submit</button>
        </form>
    );
};

export default UncontrolledForm;

				
			

Explanation of Uncontrolled Form

  • Multiple Input Fields: We use useRef to reference both the email and password fields.
  • Accessing Values on Submit: The values of the email and password inputs are accessed using emailRef.current.value and passwordRef.current.value inside the handleSubmit function.
  • No Real-Time Validation: Since this is an uncontrolled form, validation and form handling happen only when the user submits the form.

Output of Uncontrolled Form

When the user submits the form, an alert box shows the entered email and password.

When to Use Controlled vs. Uncontrolled Components

Use Controlled Components When:

  • You need real-time validation or manipulation of the input values.
  • You want more control over the form data and behavior.
  • You are dealing with complex forms where React state management simplifies validation and interaction.

Use Uncontrolled Components When:

  • You don’t need real-time interaction or validation with the input.
  • You only need the form data at the time of form submission or specific events.
  • You prefer to interact directly with the DOM and avoid extra state management.

Controlled vs. Uncontrolled Components represent two different approaches to handling form data in React. Controlled components give you more control by keeping the form state within React, allowing for real-time updates and validations. Uncontrolled components are simpler and rely on the DOM for input management, which can be beneficial for simple forms or when performance is a concern. Happy Coding!❤️

Table of Contents