Capítulo 15 de 29

Chapter 15: Listeners

Core Idea

Listeners (onChange/onBlur/onMount/onSubmit/onUnmount) run side effects in response to form/field events — deliberately separate from validators, so "reset a dependent field when this one changes" doesn't have to be smuggled into a validator function.

Key Concepts

  • Field-level listeners fire on that field's own events; form-level listeners (set in useForm's listeners) fire on every relevant event across the whole form.
  • Built-in debouncing: onChangeDebounceMs/onBlurDebounceMs apply the same debounce mechanism validators get, without needing a validator.
  • The canonical use cases are auto-save ("submit when the form becomes valid") and cascading field resets ("clear province when country changes") — neither is really a validation concern, which is why listeners exist as their own API.

Code Examples

const form = useForm({
  listeners: {
    onChange: ({ formApi }) => {
      if (formApi.state.isValid) formApi.handleSubmit() // auto-save
    },
    onChangeDebounceMs: 500,
  },
})

<form.Field
  name="country"
  listeners={{ onChange: () => form.setFieldValue('province', '') }}
>
  {(field) => <input value={field.state.value} />}
</form.Field>
  • What it demonstrates: a debounced form-level auto-save listener, plus a field-level listener that resets a dependent field — two different scopes of the same mechanism.

Key Takeaways

  1. If the goal is "do something as a side effect of a change" rather than "produce an error message," reach for a listener, not a validator that happens to return undefined.
  2. Form-level listeners see every field's events — use them for cross-cutting concerns like auto-save; field-level listeners for effects local to one field (like the country→province reset).
  3. onChangeDebounceMs/onBlurDebounceMs mirror validators' async debounce options but apply to listeners specifically — set them independently if a listener needs different timing than the field's validators.

Connects To

  • Ch013 Linked Fields: a related but distinct mechanism — that's for validation dependencies, this is for side-effect dependencies.
  • Ch017 Submission Handling: formApi.handleSubmit(), used here for auto-save.