UNPKG

@matthew.ngo/reform

Version:

A flexible and powerful React form management library with advanced validation, state observation, and multi-group support

339 lines (263 loc) 11.2 kB
# Reform Error Handling Reform provides a comprehensive error handling system that helps you manage, format, and display form errors effectively. This document covers the error handling capabilities of Reform. ## Table of Contents - [Overview](#overview) - [Error Formatting](#error-formatting) - [Error Boundaries](#error-boundaries) - [Custom Error Renderers](#custom-error-renderers) - [Error Transformation](#error-transformation) - [API Reference](#api-reference) ## Overview Reform's error handling system consists of several components: 1. **Error Formatting**: Customize how error messages are displayed 2. **Error Boundaries**: Catch and handle errors in form components 3. **Custom Error Renderers**: Create field-specific error displays 4. **Error Transformation**: Transform error messages before display ## Error Formatting The `useErrorFormatter` hook provides utilities for formatting error messages with consistent styling and content. ### Basic Usage ```tsx import { useReform, useErrorFormatter } from '@reform/core'; const MyForm = () => { const form = useReform<UserForm>(config); const errorFormatter = useErrorFormatter(form, { format: 'html', includeLabels: true, }); // Format a field error const formattedError = errorFormatter.formatFieldError( 'email', 'Invalid email format', 0 // group index ); return ( <div> {/* Display the formatted error */} <div dangerouslySetInnerHTML={{ __html: formattedError.content }} /> </div> ); }; ``` ### Configuration Options The error formatter can be configured with the following options: | Option | Type | Default | Description | | ---------------- | ---------------------------- | --------- | ----------------------------------------------- | | format | `'plain' \| 'html' \| 'jsx'` | `'plain'` | Format of error messages | | includeLabels | `boolean` | `true` | Include field labels in error messages | | includeRuleNames | `boolean` | `false` | Include validation rule names in error messages | ## Error Boundaries Reform provides error boundary components to catch and handle errors in form components. ### FormErrorBoundary Component The `FormErrorBoundary` component catches errors in its children and displays a fallback UI. ```tsx import { useReform, FormErrorBoundary, RecoveryStrategy } from '@reform/core'; const MyForm = () => { const form = useReform<UserForm>(config); const groups = form.getGroups(); return ( <FormErrorBoundary formGroups={groups} onError={(error, errorInfo) => console.error(error)} defaultRecoveryStrategy={RecoveryStrategy.RESET_FORM} FallbackComponent={({ errorInfo, resetErrorBoundary, recover }) => ( <div> <h2>Something went wrong!</h2> <pre>{errorInfo.error.message}</pre> <button onClick={() => recover(RecoveryStrategy.RESET_FORM)}> Reset Form </button> </div> )} > {/* Form components */} </FormErrorBoundary> ); }; ``` ### useFormErrorBoundary Hook For a more convenient API, you can use the `useFormErrorBoundary` hook: ```tsx import { useReform, useFormErrorBoundary } from '@reform/core'; const MyForm = () => { const form = useReform<UserForm>(config); const groups = form.getGroups(); const ErrorBoundary = useFormErrorBoundary(groups, { onError: error => console.error(error), FallbackComponent: MyCustomErrorComponent, }); return <ErrorBoundary>{/* Form components */}</ErrorBoundary>; }; ``` ### Recovery Strategies Reform provides several recovery strategies for error boundaries: | Strategy | Description | | ----------------- | ----------------------------------------- | | `RESET_FORM` | Reset the form to its initial state | | `RETRY_OPERATION` | Retry the operation that caused the error | | `IGNORE` | Ignore the error and continue | | `CUSTOM` | Use a custom recovery function | ## Custom Error Renderers Reform allows you to register custom error renderers for specific fields using the `useReformErrorRenderer` hook. ```tsx import { useReform, useReformErrorRenderer } from '@reform/core'; import { useEffect } from 'react'; const MyForm = () => { const form = useReform<UserForm>(config); const errorRenderer = useReformErrorRenderer(form); // Register a custom renderer for email fields useEffect(() => { const unregister = errorRenderer.registerErrorRenderer({ field: 'email', renderer: ({ error }) => ( <div className="email-error"> <span className="icon">⚠️</span> <span className="message">{error}</span> </div> ), }); return unregister; }, []); return ( <form> <input {...form.register(0, 'email')} /> {/* Render the field error with the custom renderer */} {errorRenderer.renderFieldError(0, 'email')} </form> ); }; ``` ## Error Transformation You can transform error messages before they are displayed using the `registerTransformer` method of the `useErrorFormatter` hook. ```tsx import { useReform, useErrorFormatter } from '@reform/core'; import { useEffect } from 'react'; const MyForm = () => { const form = useReform<UserForm>(config); const errorFormatter = useErrorFormatter(form); // Register a custom transformer for email fields useEffect(() => { errorFormatter.registerTransformer('email', { transform: (message, fieldPath, context) => { // Add a prefix to all email error messages return { content: `Email Error: ${message}`, format: 'html', fieldPath, meta: { ...context.group, groupIndex: context.groupIndex, }, }; }, }); }, []); return <form>{/* Form fields */}</form>; }; ``` ## API Reference ### useErrorFormatter ```typescript function useErrorFormatter<T extends Record<string, any>>( reform: ReformReturn<T>, initialConfig?: Partial<ErrorFormatConfig> ): FormErrorFormatter<T>; ``` #### Parameters | Parameter | Type | Description | | ------------- | ---------------------------- | ---------------------------------- | | reform | `ReformReturn<T>` | Reform hook return value | | initialConfig | `Partial<ErrorFormatConfig>` | Initial error format configuration | #### Returns Returns a `FormErrorFormatter<T>` object with the following methods: | Method | Description | | ------------------- | ------------------------------------- | | formatFieldError | Format a field error message | | formatGroupError | Format a group-level error message | | formatFormError | Format a form-level error message | | registerTransformer | Register a custom error transformer | | updateFormatConfig | Update the error format configuration | ### FormErrorBoundary ```typescript class FormErrorBoundary<T extends Record<string, any>> extends React.Component<ErrorBoundaryProps<T>, ErrorBoundaryState<T>> ``` #### Props | Prop | Type | Description | | ----------------------- | ---------------------------------------------------- | ----------------------------------------------------- | | children | `React.ReactNode` | Children to render | | FallbackComponent | `React.ComponentType<ErrorFallbackProps<T>>` | Component to render when an error occurs | | fallbackRender | `(props: ErrorFallbackProps<T>) => React.ReactNode` | Render prop alternative to FallbackComponent | | fallback | `React.ReactNode` | Simple fallback UI as a React Element | | onError | `(error: Error, errorInfo: React.ErrorInfo) => void` | Called when an error is caught | | onReset | `() => void` | Called when the error boundary recovers from an error | | defaultRecoveryStrategy | `RecoveryStrategy` | Default recovery strategy to apply | | onCustomRecovery | `(errorInfo: ErrorInfo<T>) => void` | Custom recovery handler | | formGroups | `FormGroup<T>[]` | Form groups to include in the error info | ### useFormErrorBoundary ```typescript function useFormErrorBoundary<T extends Record<string, any>>( formGroups: FormGroup<T>[], options?: Omit<ErrorBoundaryProps<T>, 'children' | 'formGroups'> ): React.FC<{ children: React.ReactNode }>; ``` #### Parameters | Parameter | Type | Description | | ---------- | --------------------------------------------------------- | ---------------------------------------- | | formGroups | `FormGroup<T>[]` | Form groups to include in the error info | | options | `Omit<ErrorBoundaryProps<T>, 'children' \| 'formGroups'>` | Options for the error boundary | #### Returns Returns a React component that wraps its children in an error boundary. ### useReformErrorRenderer ```typescript function useReformErrorRenderer<T extends Record<string, any>>( reform: ReformReturn<T> ): { registerErrorRenderer(config: ErrorRendererConfig<T>): () => void; renderError( field: FieldPath<T>, error: string | null, groupIndex?: number ): React.ReactNode; renderFieldError(groupIndex: number, field: FieldPath<T>): React.ReactNode; renderGroupErrors(groupIndex: number): React.ReactNode[]; }; ``` #### Parameters | Parameter | Type | Description | | --------- | ----------------- | ------------------------ | | reform | `ReformReturn<T>` | Reform hook return value | #### Returns Returns an object with methods for registering and using custom error renderers. ### ErrorTransformer ```typescript interface ErrorTransformer<T> { transform( message: string, fieldPath: FieldPath<T>, context: { group: FormGroup<T>; groupIndex: number; labels: Record<string, any>; formatConfig: ErrorFormatConfig; } ): FormattedErrorMessage; } ``` ### FormattedErrorMessage ```typescript interface FormattedErrorMessage { content: string; format: 'plain' | 'html' | 'jsx'; fieldPath?: string; fieldLabel?: string; meta?: Record<string, any>; } ``` ### RecoveryStrategy ```typescript enum RecoveryStrategy { RESET_FORM = 'reset_form', RETRY_OPERATION = 'retry_operation', IGNORE = 'ignore', CUSTOM = 'custom', } ```