High performance subscription-based form state management for React
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Core form wrapper component that provides form context, state management, and submission handling with efficient subscription-based updates.
The main Form component that wraps form elements and provides form state management through React context.
/**
* Main form wrapper component providing form context and state management
* @param props - Form configuration and render props
* @returns React element with form context
*/
const Form: <FormValues = Record<string, any>>(
props: FormProps<FormValues>
) => React.ReactElement;
interface FormProps<FormValues = Record<string, any>>
extends Config<FormValues>,
RenderableProps<FormRenderProps<FormValues>> {
/** Form state subscription configuration */
subscription?: FormSubscription;
/** Form decorators for additional functionality */
decorators?: Decorator<FormValues>[];
/** External form API instance */
form?: FormApi<FormValues>;
/** Custom equality function for initial values comparison */
initialValuesEqual?: (
a?: Record<string, any>,
b?: Record<string, any>
) => boolean;
}
interface FormRenderProps<FormValues = Record<string, any>>
extends FormState<FormValues> {
/** Form submission handler with event handling */
handleSubmit: (
event?: SubmitEvent
) => Promise<Record<string, any> | undefined> | undefined;
/** Form API instance for programmatic control */
form: FormApi<FormValues>;
}Usage Examples:
import React from "react";
import { Form } from "react-final-form";
// Basic form with render prop
function BasicForm() {
return (
<Form
onSubmit={(values) => console.log(values)}
render={({ handleSubmit, pristine, invalid }) => (
<form onSubmit={handleSubmit}>
{/* form fields */}
<button type="submit" disabled={pristine || invalid}>
Submit
</button>
</form>
)}
/>
);
}
// Form with initial values and validation
function ValidatedForm() {
const validate = (values: any) => {
const errors: any = {};
if (!values.firstName) {
errors.firstName = "Required";
}
return errors;
};
return (
<Form
onSubmit={(values) => console.log(values)}
initialValues={{ firstName: "John" }}
validate={validate}
render={({ handleSubmit, form, submitting, values }) => (
<form onSubmit={handleSubmit}>
{/* form fields */}
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" onClick={form.reset}>
Reset
</button>
<pre>{JSON.stringify(values, null, 2)}</pre>
</form>
)}
/>
);
}
// Form with children function
function ChildrenForm() {
return (
<Form onSubmit={(values) => console.log(values)}>
{({ handleSubmit, submitting }) => (
<form onSubmit={handleSubmit}>
{/* form fields */}
<button type="submit" disabled={submitting}>
Submit
</button>
</form>
)}
</Form>
);
}The Form component supports customizable subscriptions to optimize rendering performance by only updating when specific form state changes occur.
interface FormSubscription {
active?: boolean;
dirty?: boolean;
dirtyFields?: boolean;
dirtySinceLastSubmit?: boolean;
error?: boolean;
errors?: boolean;
hasSubmitErrors?: boolean;
hasValidationErrors?: boolean;
initialValues?: boolean;
invalid?: boolean;
modified?: boolean;
modifiedSinceLastSubmit?: boolean;
pristine?: boolean;
submitError?: boolean;
submitErrors?: boolean;
submitFailed?: boolean;
submitSucceeded?: boolean;
submitting?: boolean;
touched?: boolean;
valid?: boolean;
validating?: boolean;
values?: boolean;
visited?: boolean;
}Usage Example:
import { Form } from "react-final-form";
function OptimizedForm() {
return (
<Form
onSubmit={(values) => console.log(values)}
subscription={{ submitting: true, pristine: true, invalid: true }}
render={({ handleSubmit, submitting, pristine, invalid }) => (
<form onSubmit={handleSubmit}>
{/* Only re-renders when submitting, pristine, or invalid changes */}
<button type="submit" disabled={submitting || pristine || invalid}>
Submit
</button>
</form>
)}
/>
);
}The Form component accepts all configuration options from the underlying Final Form library through the Config interface.
interface Config<FormValues = Record<string, any>> {
/** Debug mode for development */
debug?: (state: FormState<FormValues>, action: string) => void;
/** Whether to destroy field state when field is unregistered */
destroyOnUnregister?: boolean;
/** Initial form values */
initialValues?: Partial<FormValues>;
/** Whether to keep dirty values when reinitializing */
keepDirtyOnReinitialize?: boolean;
/** Custom mutators for form state manipulation */
mutators?: Record<string, Mutator<FormValues>>;
/** Form submission handler */
onSubmit: (
values: FormValues,
form: FormApi<FormValues>,
callback?: (errors?: SubmissionErrors) => void
) => SubmissionErrors | Promise<SubmissionErrors> | undefined | void;
/** Form-level validation function */
validate?: (values: FormValues) => ValidationErrors | Promise<ValidationErrors>;
/** Values to validate on each change */
validateOnBlur?: boolean;
}Forms provide comprehensive error handling through multiple error sources and clear error state management.
interface FormState<FormValues = Record<string, any>> {
/** Current form validation errors */
errors?: ValidationErrors;
/** Submission errors from the last submit attempt */
submitErrors?: SubmissionErrors;
/** General submission error */
submitError?: any;
/** Whether the last submission failed */
submitFailed?: boolean;
/** Whether the last submission succeeded */
submitSucceeded?: boolean;
/** Whether form has validation errors */
hasValidationErrors?: boolean;
/** Whether form has submission errors */
hasSubmitErrors?: boolean;
}
type ValidationErrors = Record<string, any>;
type SubmissionErrors = Record<string, any>;Usage Example:
function ErrorHandlingForm() {
const onSubmit = async (values: any) => {
// Simulate server validation
if (values.email === "taken@example.com") {
return { email: "Email already taken" };
}
// Success case
console.log("Submitted:", values);
};
return (
<Form
onSubmit={onSubmit}
render={({ handleSubmit, submitError, hasSubmitErrors, errors }) => (
<form onSubmit={handleSubmit}>
{submitError && <div className="error">{submitError}</div>}
{hasSubmitErrors && (
<div className="error">Please fix the errors below</div>
)}
{/* form fields */}
</form>
)}
/>
);
}Install with Tessl CLI
npx tessl i tessl/npm-react-final-form