Re-render form if array changes with React-hook-form

3 min read 04-10-2024
Re-render form if array changes with React-hook-form


Keep Your React Forms in Sync: Re-rendering with React Hook Form and Array Changes

Ever struggled with keeping your React forms up-to-date when the underlying data array changes? This is a common issue when using React Hook Form (RHF) – a popular library for building powerful and flexible forms.

Let's break down the problem and explore some solutions to ensure your forms re-render seamlessly whenever your array data changes.

The Scenario:

Imagine you're building a form to manage a list of items, like a shopping cart. The form uses RHF for input management, and you have an array to store the items. When a new item is added or removed from this array, you want the form to reflect those changes automatically, updating the number of inputs or removing outdated ones.

The Original Code (Without Re-render):

import React, { useState } from "react";
import { useForm } from "react-hook-form";

function ShoppingCartForm() {
  const [items, setItems] = useState([]);
  const { register, handleSubmit } = useForm();

  const addItem = () => {
    setItems([...items, { name: '', quantity: '' }]);
  };

  const removeItem = (index) => {
    setItems(items.filter((_, i) => i !== index));
  };

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {items.map((item, index) => (
        <div key={index}>
          <input {...register(`items.${index}.name`)} placeholder="Name" />
          <input {...register(`items.${index}.quantity`)} placeholder="Quantity" />
          <button type="button" onClick={() => removeItem(index)}>Remove</button>
        </div>
      ))}
      <button type="button" onClick={addItem}>Add Item</button>
      <button type="submit">Submit</button>
    </form>
  );
}

export default ShoppingCartForm;

In this example, adding or removing an item from the items array will not automatically re-render the form. This is because RHF does not inherently trigger re-renders when the items array changes.

The Problem:

RHF relies on its internal state to manage form data. It doesn't directly watch for changes outside its own scope, like changes in the items array. As a result, the form won't update its UI when the array is modified.

The Solution: Force a Re-render:

To address this, we need to signal RHF to re-render the form whenever the items array is modified. We can achieve this by using the useMemo hook from React:

import React, { useState, useMemo } from "react";
import { useForm } from "react-hook-form";

function ShoppingCartForm() {
  const [items, setItems] = useState([]);
  const { register, handleSubmit } = useForm();

  // Create a memoized version of the items array
  const memoizedItems = useMemo(() => items, [items]);

  const addItem = () => {
    setItems([...items, { name: '', quantity: '' }]);
  };

  const removeItem = (index) => {
    setItems(items.filter((_, i) => i !== index));
  };

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {memoizedItems.map((item, index) => (
        <div key={index}>
          <input {...register(`items.${index}.name`)} placeholder="Name" />
          <input {...register(`items.${index}.quantity`)} placeholder="Quantity" />
          <button type="button" onClick={() => removeItem(index)}>Remove</button>
        </div>
      ))}
      <button type="button" onClick={addItem}>Add Item</button>
      <button type="submit">Submit</button>
    </form>
  );
}

export default ShoppingCartForm;

The useMemo hook creates a memoized version of the items array, which RHF will then observe for changes. Whenever the items array changes, useMemo will create a new memoized version, triggering a re-render of the form.

Key Points:

  • useMemo is crucial: It ensures that whenever the items array is updated, RHF recognizes the change and re-renders the form.
  • Optimized Re-renders: useMemo will only re-create the memoized array when the items array changes, preventing unnecessary re-renders and improving performance.
  • Flexibility: This approach works well for various use cases, including adding, removing, and updating items within the array.

Conclusion:

By understanding how RHF manages its state and leveraging the power of useMemo, you can ensure your forms stay synchronized with dynamic array data. This allows you to build more interactive and user-friendly forms that seamlessly adapt to changes.