A form submit is an event, while validity can usually be derived from its current values. React interview questions about forms often expose problems caused by duplicated validation state or a request triggered by an Effect.

This illustrative feedback form receives a save function. It does not claim to implement a production API, authentication or server-side deduplication. Its job is to show controlled input, local pending behavior and a recoverable error.

How can the form keep one source of truth?

import { useRef, useState } from 'react';

export default function FeedbackForm({ save }) {
  const [text, setText] = useState('');
  const [pending, setPending] = useState(false);
  const [message, setMessage] = useState('');
  const inFlight = useRef(false);
  const valid = text.trim().length >= 3;

  async function submit(event) {
    event.preventDefault();
    if (!valid || inFlight.current) return;
    inFlight.current = true;
    setPending(true);
    setMessage('');
    try {
      await save(text.trim());
      setText('');
      setMessage('Feedback saved.');
    } catch {
      setMessage('Could not save. Your text is still here.');
    } finally {
      inFlight.current = false;
      setPending(false);
    }
  }

  return <form onSubmit={submit}>
    <label htmlFor="feedback">Feedback</label>
    <textarea id="feedback" value={text} disabled={pending}
      onChange={event => setText(event.target.value)} />
    <p>Enter at least three non-space characters.</p>
    <button type="submit" disabled={!valid || pending}>
      {pending ? 'Saving...' : 'Save feedback'}
    </button>
    <p role="status">{message}</p>
  </form>;
}

The value and onChange keep the input controlled. Valid is a calculation, not another state variable. The handler preserves the text when save fails and clears it only after success. Disabling editing during this small example avoids erasing an edit made while a save was pending.

Why use onSubmit rather than only onClick?

The form owns submission. A submit handler supports the browser's form interaction model, including submission through a submit button. Using only a click handler can miss other submission paths. Preventing the default here keeps this example on the same page while its injected save function runs.

What does the ref guard add?

The ref changes immediately inside the handler, so another handler call before a rerender can see a request is in flight. Pending state controls the visible interface. This local guard does not guarantee exactly-once processing across tabs, retries or network failures. A consequential server operation needs an appropriate server-side idempotency design.

Where does validation belong?

Client validation gives early feedback. The server validates again because clients can be changed or bypassed. Keep the rules consistent where practical, but do not trust a disabled button as a security boundary.

If validation becomes more detailed, associate field errors with their controls and explain how to correct them. A single generic red border is not enough. Do not mark untouched fields invalid merely to fill the page with errors.

How do you test the asynchronous cases?

  • Use a save stub that stays pending and confirm the button and input are disabled.
  • Resolve it and check the success message and cleared input.
  • Reject it and confirm text remains available for retry.
  • Submit blank or short text and verify save was not called.
  • Trigger two immediate submissions and check the local guard permits one pending call.

Use a controllable promise rather than a fixed sleep. It lets the test choose the exact pending, success and failure moments.

Explain the boundary

The component owns interaction feedback. The save function owns transport, and the server owns authoritative validation and storage. Naming those responsibilities makes the answer more useful than listing hooks without explaining the behavior.

References and next practice

react.dev — react events · react.dev — react effects

react question collection · Browse interview topics · Practise a question in Interview Challenge · How to Answer Technical Interview Questions Out Loud