简体   繁体   English

react-hook-form FormProvider 与受控组件的性能(或者,如何记忆受控组件)

[英]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.我正在使用FormProvider来处理动态创建的“深度嵌套”表单。 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. FormProvider 性能文档说,“...[FormProvider] 还会导致组件树在 React Hook Form 触发 state 更新时触发重新渲染”,并建议记忆组件来解决这个问题。 I'm using controlled components (MUI) and can't figure out how to do the memoizing.我正在使用受控组件 (MUI),但不知道如何进行记忆。 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".Controller会引发 TypeDef 错误,即“props.render 不是函数”。 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".它警告memo “第一个参数必须是一个组件。而不是接收:对象”,并且ConnectForm (或第二个实例中的FormContent )抛出一个错误,“对象作为 React 子项无效”。

How do I go about implementing this "performance enhancement" with controlled component?我如何使用受控组件实现这种“性能增强”?

Hey not sure if you are still having this issue but I've built a new form library that doesn't come with any of these issues.嘿,不确定您是否仍然遇到此问题,但我已经构建了一个新的表单库,它没有任何这些问题。 You can have nested components without needing to do anything special.您可以拥有嵌套组件而无需执行任何特殊操作。

Its' in beta and currently being worked on but it might solve the issues you are having.它处于测试阶段,目前正在开发中,但它可能会解决您遇到的问题。

You can check it out here if you feel so inclined: https://react-formz.zerry.dev/docs/intro/如果您愿意,可以在这里查看: https://react-formz.zerry.dev/docs/intro/

import {
  Form,
  TextField,
  NumberField,
  DependentTextField,
} from "@zerry/react-formz";

const NestedInput = () => {
  return (
    <TextField
        required
        name="name"
        as={({ input }) => <input {...input} />}
    />
  )
}

const MyForm = () => {
  return (
    <Form initialValues={{ name: "", age: "" }}>
      <NestedInput />
      <NumberField
        required
        name="age"
        as={({ input }) => <input {...input} />}
      />
    </Form>
  );
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM