skip to Main Content

I’m using react-hook-form inside of a Form component.

The Form component has to update its container – App component.

The From component should not have a submit button.

Therefore, a watch method of react-hook-form has to be used.

The App component preserves the data using useState hook.
I’m trying to update the data inside the App component using prop callback.
This causes an infinite loop.

App component

import { FC, useState } from 'react';

import { Form } from './Form';
export const App: FC<{ name: string }> = ({ name }) => {
  const [data, setData] = useState({ name: 'David' });
  return (
    <div>
      <h1>Hello {data.name}!</h1>
      <Form setData={setData} />
    </div>
  );
};

Form component:

import React, { useEffect } from 'react';
import { useForm } from 'react-hook-form';

export const Form = ({ setData }) => {
  const { register, watch } = useForm();
  const formData = watch();
  useEffect(() => {
    setData(formData);
  }, [formData]);

  return (
    <div>
      <h2>Form comp</h2>
      <form>
        <input name="name" {...register('name')} />
      </form>
    </div>
  );
};

Stackblitz – note – to see the infinite loop issue, change the App component and change the setData prop to the setter function.

2

Answers


  1. You are using setData to update the state in the App component every time the form data changes. However, this also triggers a re-render of the App component, leading to an infinite loop.

    If you want to update the state in the App component when the form data changes, you might want to move the form state management to the App component

    App component:

    import React, { useState } from 'react';
    import { Form } from './Form';
    
    export const App = () => {
      const [formData, setFormData] = useState({ name: 'David' });
    
      const updateFormData = (newFormData) => {
        setFormData(newFormData);
      };
    
      return (
        <div>
          <h1>Hello {formData.name}!</h1>
          <Form formData={formData} updateFormData={updateFormData} />
        </div>
      );
    };
    

    Form Component:

    import React, { useEffect } from 'react';
    import { useForm } from 'react-hook-form';
    
    export const Form = ({ formData, updateFormData }) => {
      const { register, watch } = useForm();
    
      const watchedData = watch();
    
      useEffect(() => {
        // Update the parent component's state only if the form data has changed
        if (JSON.stringify(watchedData) !== JSON.stringify(formData)) {
          updateFormData(watchedData);
        }
      }, [watchedData, formData, updateFormData]);
    
      return (
        <div>
          <h2>Form comp</h2>
          <form>
            <input name="name" {...register('name')} />
          </form>
        </div>
      );
    };
    

    Now, the form component (Form) receives the form data and a function to update it as props. It triggers the updateFormData function only if the form data has changed, preventing an infinite loop. Check StackBlitz

    Login or Signup to reply.
  2. whenever FormData is changed and it triggers a re-render, which, in turn, causes the useEffect in the Form component to be executed again, leading to an infinite loop.

    import React, { useEffect, useState } from 'react';
    import { useForm } from 'react-hook-form';
    
    export const Form = ({ setData }) => {
      const { register, watch } = useForm();
      const formData = watch();
      const [dataChanged, setDataChanged] = useState(false);
    
      useEffect(() => {
        // Check if formData is different from the data
        if (dataChanged) {
          setData(formData);
          // Reset the flag to false
          setDataChanged(false);
        }
      }, [dataChanged, formData, setData]);
    
      useEffect(() => {
        // Set the flag to true when formData changes
        setDataChanged(true);
      }, [formData]);
    
      return (
        <div>
          <h2>Form comp</h2>
          <form>
            <input name="name" {...register('name')} />
          </form>
        </div>
      );
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search