From dd22eaa5b62fca7a95bef9cb66a853d447e8bda7 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 23 Apr 2026 17:53:32 +0000 Subject: [PATCH] fix(form): stabilize renders, fix FormItem memo deps, correct useImperativeHandle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ProForm: memoize default contentRender with useCallback to avoid new function identity every render and unnecessary BaseForm content remounts - BaseForm: fix nested JSDoc on formatValues; useImperativeHandle deps use formRef instead of formRef.current; content useMemo depends on formRef - FormItem: useDeepCompareMemo depends on child fieldProps (not duplicate omit() in deps array) for correct deep-compare memoization Co-authored-by: 陈帅 --- src/form/BaseForm/BaseForm.tsx | 9 ++++----- src/form/components/FormItem/index.tsx | 14 ++++++-------- src/form/layouts/ProForm/index.tsx | 25 ++++++++++++++++--------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/form/BaseForm/BaseForm.tsx b/src/form/BaseForm/BaseForm.tsx index 87240520a562..66d70686cd27 100644 --- a/src/form/BaseForm/BaseForm.tsx +++ b/src/form/BaseForm/BaseForm.tsx @@ -390,13 +390,12 @@ function BaseFormComponents, U = Record>( nameList, ); }, - /** /** - *验字段后返回格式化之后的所有数据 + * 验字段后返回格式化之后的所有数据 * @param nameList (string|number)[] * @param omitNilParam boolean * @returns T - * + * * @example validateFieldsReturnFormatValue -> {a:{b:value}} */ validateFieldsReturnFormatValue: async ( @@ -493,7 +492,7 @@ function BaseFormComponents, U = Record>( return contentRender(wrapItems as any, submitterNode, formRef.current); } return wrapItems; - }, [grid, RowWrapper, items, contentRender, submitterNode]); + }, [grid, RowWrapper, items, contentRender, submitterNode, formRef]); const preInitialValues = usePrevious(props.initialValues); @@ -595,7 +594,7 @@ function BaseFormComponents, U = Record>( return transformedKey ? transformedKey : {}; }, }; - }, [omitNil, transformKey, formRef.current]); + }, [omitNil, transformKey, propsFormRef]); useEffect(() => { const finalValues = transformKey( formRef.current?.getFieldsValue?.(true), diff --git a/src/form/components/FormItem/index.tsx b/src/form/components/FormItem/index.tsx index dafe92623bb1..c5800cca4b08 100644 --- a/src/form/components/FormItem/index.tsx +++ b/src/form/components/FormItem/index.tsx @@ -69,20 +69,18 @@ const WithValueFomFiledProps: React.FC< ); }); + const childFieldProps = React.isValidElement(filedChildren) + ? (filedChildren.props as Record)?.fieldProps + : undefined; + const omitOnBlurAndOnChangeProps = useDeepCompareMemo( () => omit( // @ts-ignore - filedChildren?.props?.fieldProps || {}, - ['onBlur', 'onChange'], - ), - [ - omit( - // @ts-ignore - filedChildren?.props?.fieldProps || {}, + childFieldProps || {}, ['onBlur', 'onChange'], ), - ], + [childFieldProps], ); const propsValuePropName = formFieldProps[valuePropName]; diff --git a/src/form/layouts/ProForm/index.tsx b/src/form/layouts/ProForm/index.tsx index 9e4a1218cff5..65f9ce983ca1 100644 --- a/src/form/layouts/ProForm/index.tsx +++ b/src/form/layouts/ProForm/index.tsx @@ -1,6 +1,6 @@ import type { FormProps } from 'antd'; import { Form } from 'antd'; -import React from 'react'; +import React, { useCallback } from 'react'; import type { CommonFormProps } from '../../BaseForm'; import { BaseForm } from '../../BaseForm'; import { EditOrReadOnlyContext } from '../../BaseForm/EditOrReadOnlyContext'; @@ -16,17 +16,24 @@ function ProForm>( children?: React.ReactNode | React.ReactNode[]; }, ) { + const contentRender = useCallback( + ( + items: React.ReactNode[], + submitter: React.ReactNode, + _form: unknown, + ) => ( + <> + {items} + {submitter} + + ), + [], + ); + return ( { - return ( - <> - {items} - {submitter} - - ); - }} + contentRender={contentRender} {...props} /> );