Nested useForm() inputs, Self-Rendering useForm(), Yup schemas validation and React-window inputs

The <FormProvider> makes the useForm() context available to nested components. The <ConnectForm> component simplifies access to the form context. It retrieves methods from useFormContext() and passes them as props to its child render function, which uses them to register() input elements with the form.

//The <ConnectForm> children render prop function will receive
//Its {...methods} argument from the parent
const ConnectForm = ({ children }) => {
  const methods = useFormContext()
  return children({ ...methods })
}

const DeepNest = () => (
  <div>
  <ConnectForm>
    {({ register }) => (
      <div>
        <input {...register("nested1")} placeholder="Input 1" />
        <input {...register("nested2")} placeholder="Input 2" />
      </div>
    )}
  </ConnectForm>
  <Primo /> <Secondo />
  <div>
)

function Testa(){
  const methods = useForm()

  return(
    <FormProvider {...methods}>
      <form>
        <DeepNest />
        <input type="submit" />
      </form>
    </FormProvider>
  )
}
chevron-rightNested input components in the render prophashtag

The <ConnectForm> component is re-usable and can allow different useForm() methods to be extracted and used.

Which is symilar of what we could do with the basic useFormContext().

Self-Rendering Form Components

A form composition implements the useForm() hook by leveraging its input function components. It automatically renders and registers complex forms by iterating over the React child elements.

The parent <Form> component receives the useForm() options and the onSubmit() function as explicit props, while its child elements are implicitly passed via the children prop. We iterate over these child elements, registering only the input components that have a name prop, leaving other child elements unchanged.

The child's type (its corresponding component function) and its props object are passed to createElement(). The rendered input's configuration props are created by merging the useForm() methods with the child's existing props.

This enables the dynamic rendering of form inputs, each with a specific type, and registered based on its props.

chevron-rightRender prop and input component differenceshashtag

The examples above illustrate two different approaches to creating modular forms: the render prop pattern and the use of function components.

In the render prop pattern, a function is passed as the children prop. Unlike modular components that directly return JSX, the render prop pattern delegates rendering to its prop function, with the parent controlling the output via the arguments it passes.

In a modular form, the child component renders the JSX, unlike the render prop pattern where the parent component controls the rendering function.

Implementing Yup schemas for form validation

React-Hook-Form can integrate external validation libraries, like Yup.

It uses declarative objects, such as validation schemas, to define the valid data structure instead of the inline validation rules. We use the useForm({}) resolver option to integrate the Yup validation.

The resolver function is typically implemented as a useCallback() function within a custom hook, with the schema as a dependency to prevent unnecessary re-validations.

This function validates the form data against its schema upon submission. If validation succeeds, it returns an object containing the form data and an empty errors object, which then triggers the handleSubmit function. If validation fails, the resolver converts the Yup errors to update the formState.errors object.

chevron-rightSwitching yup schemas on a formhashtag

A change to the validation schema triggers the useCallback(), creating a new validation instance. While a form submission triggers only the resolver, not the useCallback() itself.

Virtualized useForm() inputs with React-Window

The React-Window library optimizes the rendering of large lists of data through virtualization.

It renders only the items visible within the viewport, minimizing DOM updates. It mantains the complete dataset in a state, like useForm(), independent of visibility.

The react-window <VariableSizeList> component virtualizes the rendering of inputs from a dataset. The viewport size can be set directly or determined automatically using the <AutoSizer> parent component, which provides the available height and width via a render prop.

The <List> component renders each individual item using a child function component, which receives the item's index, a style object for positioning, and the data array passed as itemData, as key props.

The style prop, specific to each rendered item, can be destructured for further customization and defaults to position: absolute and left: 0.

Inputs registered in the <List> function component are stored independently in the formState. The virtualized mounting and unmounting of these inputs doesn't affect their current data.

chevron-right--> useFieldArray on virtualizedhashtag

The useFieldArray() methods allows us to edit a viertualized list.

The itemKey prop in the component provides each virtualized item with its unique field ID, which updates only changed items within the list.

The Input validation doesn't cover unmounted virtualized inputs; apply it on form submission, where the complete dataset will be available.

1

1

1

1

1

Last updated