How to Update Uncontrolled Components in React

Uncontrolled components in React rely on the DOM to store and manage their state, rather than using React’s internal state. While they are typically designed to be self-managing, you can update them programmatically when necessary. This article covers the primary methods for updating uncontrolled components in React, including using React refs to manipulate the DOM directly, leveraging the key prop for force-resetting, and managing initial values with default properties.

1. Updating Values Programmatically Using Refs

The most common way to update an uncontrolled component is by using a React ref. By attaching a ref to the form element, you gain direct access to the underlying DOM node, allowing you to modify its value directly.

import { useRef } from 'react';

function UncontrolledInput() {
  const inputRef = useRef(null);

  const updateValue = () => {
    // Directly updating the DOM node's value
    if (inputRef.current) {
      inputRef.current.value = 'New Updated Value';
    }
  };

  return (
    <div>
      <input ref={inputRef} type="text" defaultValue="Initial Value" />
      <button onClick={updateValue}>Update Input</button>
    </div>
  );
}

In this example, clicking the button directly alters the value property of the HTML input element without triggering a React state re-render.

2. Resetting the Component Using the key Prop

If you need to completely reset or update an uncontrolled component to a new default value from a parent component, you can use the key prop. Changing the key forces React to unmount the old component and mount a brand-new instance, re-initializing it with the new defaultValue.

import { useState } from 'react';

function ParentComponent() {
  const [resetId, setResetId] = useState(0);

  const handleReset = () => {
    setResetId(prevId => prevId + 1);
  };

  return (
    <div>
      {/* Changing the key forces the input to remount with the defaultValue */}
      <input key={resetId} type="text" defaultValue="Fresh Start Value" />
      <button onClick={handleReset}>Reset Input Field</button>
    </div>
  );
}

This technique is highly effective when you need to clear forms or sync an uncontrolled element with new data fetched from an external source.

3. Setting Initial Updates with defaultValue

When working with uncontrolled components, you should avoid using the value attribute, as doing so turns the component into a controlled one. Instead, use defaultValue (or defaultChecked for checkboxes and radio buttons). This sets the initial value but leaves the DOM in control of subsequent updates.

function DefaultValueExample() {
  return (
    <input 
      type="text" 
      defaultValue="This is the initial, editable value" 
    />
  );
}

If the defaultValue prop changes after the initial mount, React will not update the value in the DOM. To handle subsequent updates, you must pair this approach with the key prop method described above.