The <errorMessage> component, useWatch() hook and multi-page funnel useForm().

The <errorMessage> is an imported component used to render an input formState error.

npm install @hookform/error-message
import { ErrorMessage } from "@hookform/error-message"

Its properties are:

  • name: The input we render the errors from, required.

  • errors: The useForm() formState errors object.

  • render: The fucntion component that renders the error in the DOM.

  • as: alternative wrapper component for the error message.

It can render errors from external components and <Controller/> inputs in the form.

//We need the criteriaMode to render multiple errors
const {register, formState: {errors}}= useForm({ criteriaMode: "all" })

<form>
  <input {...methods.register("Terzo", {
    minLength: { value: 5, message: "too long sorry" },
    validate: (value)=>{ return (value.length>1) && "Too long again" }
  })} />

  <ErrorMessage errors={methods.formState.errors} name="Terzo" as="p" />        

  <ErrorMessage
    errors={methods.formState.errors} name="Terzo"
    render={({ message }) => <p className="text-warning">{message}</p>}
  />
</form>
Multiple errors in <ErrorMessage> input

We iterate through multiple error messages using the Object.entries() method. Since the rendered elements are treated as a list, we extract the key argument to use as the key for each element.

The useWatch() method

The useWatch() custom hook subscribes to changes in the selected input, but unlike the watch() method, it limits re-renders to only the component in which it is declared. On the first render, it returns the defaultValues provided to useForm().

The useWatch() properties are:

  • name: string/array. The input currently being watched.

  • control: The useForm() control object.

  • defaultValue: string/object. Once declared it replaces the useForm() defaultValues.

  • disabled: boolean. It disables the subscription to the watched input value.

  • Exact: boolean. If set default false, it will trigger the useWatch() for inputs that share the initial part of the name property (e.g., "primo222" for "primo"), but it will not update the value.

chevron-rightThe watch() and useWatch() rules for external input componentshashtag

The useWatch() hook method can trigger a form re-render that unfocuses the input onChange() event.

useWatch: If it is declared within the form component, about an input component.

watch: If set in an input component watching its own input. If set in the form component about an input component.

In those intances, we need to render the input components outside the form component.

Multi-Step Form with local-state-machine

A funnel, or wizard form, segments a complex form among multiple pages. The local-state-machinearrow-up-right library manages the form state in sessionStorage, providing context across all funnel pages.

The createStore() method initializes the form data in sessionStorage. It accepts two object arguments: one for the initial default values of the form state, and another for its configuration properties.

name: string. Sets the name of the sessionStorage state object. Defaults to __LSM__.

middlewares: array of functions. Contains functions that wil execute after useStateMachine() functions. They won't trigger if the sessionStorage state is modified externally.

Each component within the form funnel needs to call the useStateMachine() custom hook. The useStateMachine() returns its current form state and an action object containing the functions declared in the hook, which are used to interact with the shared form context.

Action functions can be triggered within any event handler. On form submit, they update the current state using the form data as the payload.

We can use the sessionStorage's methods to remove state objects.

The updated state value persists across navigation, it can be used as the input's defaultValue, allowing users to retain their previous input values.

The <StateMachineProvider/> makes the state context available to all components rendered within the React Router.

If createStorage() contains nested objects, you need to destructure them within the update function to correctly modify their values.

Funnel JS example

Last updated