or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

field-registration.mdform-actions.mdform-creation.mdindex.mdstate-management.mdutilities.mdvalidation.md
tile.json

state-management.mddocs/

State Management

Comprehensive form and field state management with subscription-based updates for optimal performance and minimal re-renders.

Capabilities

Form State Access

Methods for accessing and subscribing to form state changes.

interface FormApi<FormValues, InitialFormValues> {
  /** Get current form state synchronously */
  getState(): FormState<FormValues, InitialFormValues>;
  
  /** Subscribe to form state changes with selective subscription */
  subscribe(
    subscriber: FormSubscriber<FormValues, InitialFormValues>,
    subscription: FormSubscription
  ): Unsubscribe;
  
  /** Subscribe to form state with callback-based approach */
  subscribeFormState(
    onChange: () => void,
    subscription: FormSubscription
  ): Unsubscribe;
  
  /** Get a snapshot of current form state */
  getFormSnapshot(): FormState<FormValues, InitialFormValues>;
  
  /** Batch multiple operations to prevent multiple notifications */
  batch(fn: () => void): void;
}

Usage Examples:

import { createForm } from "final-form";

const form = createForm({
  onSubmit: (values) => console.log(values)
});

// Get current state
const currentState = form.getState();
console.log('Form is valid:', currentState.valid);

// Subscribe to specific form state properties
const unsubscribe = form.subscribe(
  (formState) => {
    console.log('Values changed:', formState.values);
    console.log('Form is dirty:', formState.dirty);
  },
  { values: true, dirty: true } // Only get notified of these changes
);

// Callback-based subscription
const unsubscribeCallback = form.subscribeFormState(
  () => {
    const snapshot = form.getFormSnapshot();
    console.log('Form state changed:', snapshot);
  },
  { valid: true, submitting: true }
);

// Batch operations to prevent multiple notifications
form.batch(() => {
  form.change('firstName', 'John');
  form.change('lastName', 'Doe');
  form.change('email', 'john@example.com');
  // Only one notification will be sent after all changes
});

Form State Interface

Complete form state object with all available properties.

interface FormState<
  FormValues = Record<string, any>,
  InitialFormValues extends Partial<FormValues> = Partial<FormValues>
> {
  /** Currently active (focused) field name */
  active?: keyof FormValues;
  
  /** Whether any field has been modified from initial values */
  dirty?: boolean;
  
  /** Object indicating which specific fields are dirty */
  dirtyFields?: { [key: string]: boolean };
  
  /** Which fields have been modified since last submit */
  dirtyFieldsSinceLastSubmit?: { [key: string]: boolean };
  
  /** Whether form has been modified since last submission */
  dirtySinceLastSubmit?: boolean;
  
  /** Form-level error (when using FORM_ERROR) */
  error?: any;
  
  /** Field-level validation errors */
  errors?: ValidationErrors;
  
  /** Whether form has submission errors */
  hasSubmitErrors?: boolean;
  
  /** Whether form has validation errors */
  hasValidationErrors?: boolean;
  
  /** Initial values provided at form creation */
  initialValues?: InitialFormValues;
  
  /** Whether form has any validation errors */
  invalid?: boolean;
  
  /** Object indicating which fields have been modified */
  modified?: { [key: string]: boolean };
  
  /** Whether form has been modified since last submission */
  modifiedSinceLastSubmit?: boolean;
  
  /** Whether form is in its initial, unmodified state */
  pristine?: boolean;
  
  /** Form-level submission error */
  submitError?: any;
  
  /** Field-level submission errors */
  submitErrors?: SubmissionErrors;
  
  /** Whether last submission attempt failed */
  submitFailed?: boolean;
  
  /** Whether last submission attempt succeeded */
  submitSucceeded?: boolean;
  
  /** Whether form is currently being submitted */
  submitting?: boolean;
  
  /** Object indicating which fields have been touched */
  touched?: { [key: string]: boolean };
  
  /** Whether form passes all validation */
  valid?: boolean;
  
  /** Whether form is currently being validated */
  validating?: boolean;
  
  /** Current form values */
  values?: FormValues;
  
  /** Object indicating which fields have been visited */
  visited?: { [key: string]: boolean };
}

Form Subscription Interface

Subscription object for controlling which form state properties trigger updates.

interface FormSubscription {
  active?: boolean;
  dirty?: boolean;
  dirtyFields?: boolean;
  dirtyFieldsSinceLastSubmit?: boolean;
  dirtySinceLastSubmit?: boolean;
  modifiedSinceLastSubmit?: boolean;
  error?: boolean;
  errors?: boolean;
  hasSubmitErrors?: boolean;
  hasValidationErrors?: boolean;
  initialValues?: boolean;
  invalid?: boolean;
  modified?: boolean;
  pristine?: boolean;
  submitError?: boolean;
  submitErrors?: boolean;
  submitFailed?: boolean;
  submitting?: boolean;
  submitSucceeded?: boolean;
  touched?: boolean;
  valid?: boolean;
  validating?: boolean;
  values?: boolean;
  visited?: boolean;
}

Subscription Examples:

// Subscribe only to validation state changes
form.subscribe(
  (state) => {
    if (state.invalid) {
      showErrorMessage('Please fix validation errors');
    }
  },
  { valid: true, invalid: true, errors: true }
);

// Subscribe to submission state
form.subscribe(
  (state) => {
    if (state.submitting) {
      showLoadingSpinner();
    } else if (state.submitSucceeded) {
      showSuccessMessage();
    } else if (state.submitFailed) {
      showErrorMessage('Submission failed');
    }
  },
  { submitting: true, submitSucceeded: true, submitFailed: true }
);

// Subscribe to form dirty state for unsaved changes warning
form.subscribe(
  (state) => {
    if (state.dirty) {
      enableUnsavedChangesWarning();
    } else {
      disableUnsavedChangesWarning();
    }
  },
  { dirty: true, pristine: true }
);

Subscriber Function Types

Type definitions for form state subscriber functions.

type FormSubscriber<
  FormValues = Record<string, any>,
  InitialFormValues extends Partial<FormValues> = Partial<FormValues>
> = (state: FormState<FormValues, InitialFormValues>) => void;

type Unsubscribe = () => void;

Form Subscription Items

List of all available form subscription properties for reference.

const formSubscriptionItems: readonly string[];

The formSubscriptionItems array contains: ["active", "dirty", "dirtyFields", "dirtyFieldsSinceLastSubmit", "dirtySinceLastSubmit", "error", "errors", "hasSubmitErrors", "hasValidationErrors", "initialValues", "invalid", "modified", "modifiedSinceLastSubmit", "pristine", "submitting", "submitError", "submitErrors", "submitFailed", "submitSucceeded", "touched", "valid", "validating", "values", "visited"]

Usage Example:

import { formSubscriptionItems } from "final-form";

// Create a subscription that includes all properties
const fullSubscription = formSubscriptionItems.reduce((acc, item) => {
  acc[item] = true;
  return acc;
}, {});

// Subscribe to all form state changes
form.subscribe(
  (state) => console.log('Full form state:', state),
  fullSubscription
);

Performance Optimization

The subscription system is designed for optimal performance:

// ❌ Bad: Subscribing to all changes causes unnecessary re-renders
form.subscribe(
  (state) => updateUI(state),
  { 
    values: true, 
    errors: true, 
    dirty: true, 
    submitting: true, 
    valid: true,
    // ... many more properties
  }
);

// ✅ Good: Subscribe only to properties you actually use
form.subscribe(
  (state) => {
    if (state.submitting) {
      showSpinner();
    }
  },
  { submitting: true } // Only get notified when submitting changes
);

// ✅ Good: Separate subscriptions for different UI concerns
form.subscribe(
  (state) => updateFormValues(state.values),
  { values: true }
);

form.subscribe(
  (state) => updateValidationErrors(state.errors),
  { errors: true }
);