'react-hook-form FormProvider performance with controlled components (or, how to memoize controlled components)

I'm using FormProvider to deal with a dynamically created, "deeply nested" form. The FormProvider Performance documentation says, "...[FormProvider] also causes the component tree to trigger a re-render when React Hook Form triggers a state update", and recommends memoizing the components to address this. I'm using controlled components (MUI) and can't figure out how to do the memoizing. Here's the deeply-nested portion that returns the form input controls:

const FormContent = ( {content} ) => { 
  return content.map((item, i) => { 
    const name = item.component.props.name;

    return ( 
      <ConnectForm key={name + '_' + i}>
        {() => <Controller
          name={name}
          defaultValue=''
          render={({ field: { onChange, onBlur, value, name, ref },
                     fieldState: { error },
                     formState: { isDirty } }) => { 
              return React.cloneElement(item.component, { 
                name: name,
                value: value,
                onChange: onChange,
                inputRef: ref,
                error: isDirty && !!error,
                helperText: isDirty && error?.message,
                FormHelperTextProps: { error: true } 
              })
            } 
          } 
        />}
      </ConnectForm>
    );
  });
}

I tried to do

  render={ 
    memo(({ field: { onChange, onBlur, value, name, ref },
      return React.cloneElement(item.component, { 
        ...
      })
    },
    (prevProps, nextProps) =>
      prevProps.formState.isDirty === nextProps.formState.isDirty)
  } 

but Controller throws a TypeDef error that "props.render is not a function". If I do

{() => memo(<Controller
  ...
/>,
(prevProps, nextProps) =>
  prevProps.formState.isDirty === nextProps.formState.isDirty
)}

or

  memo(<ConnectForm key={name + '_' + i}>
    {() => <Controller
      ... 
    />}
  </ConnectForm>,
    (prevProps, nextProps) =>
      prevProps.formState.isDirty === nextProps.formState.isDirty
  )

It warns for memo that "The first argument must be a component. Instead received: object", and ConnectForm (or FormContent in the 2nd instance) throws an error, "Objects are not valid as a React child".

How do I go about implementing this "performance enhancement" with controlled component?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source