feat: Form.Item no longer need fieldKey anymore (#32689)

* chore:Update Form to remove fieldKey

* fix: fieldKey cache logic

* test: Update snapshot

* chore: clean up
This commit is contained in:
二货机器人 2021-10-29 18:24:50 +08:00 committed by GitHub
parent 5a1d8159b1
commit 184402a9bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 202 additions and 24 deletions

View File

@ -1,9 +1,8 @@
import * as React from 'react';
import { useContext } from 'react';
import classNames from 'classnames';
import { Field, FormInstance } from 'rc-field-form';
import { Field, FormInstance, FieldContext, ListContext } from 'rc-field-form';
import { FieldProps } from 'rc-field-form/lib/Field';
import FieldContext from 'rc-field-form/lib/FieldContext';
import { Meta, NamePath } from 'rc-field-form/lib/interface';
import { supportRef } from 'rc-util/lib/ref';
import omit from 'rc-util/lib/omit';
@ -62,7 +61,7 @@ export interface FormItemProps<Values = any>
initialValue?: any;
messageVariables?: Record<string, string>;
tooltip?: LabelTooltipType;
/** Auto passed by List render props. User should not use this. */
/** @deprecated No need anymore */
fieldKey?: React.Key | React.Key[];
}
@ -86,7 +85,6 @@ function genEmptyMeta(): Meta {
function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElement {
const {
name,
fieldKey,
noStyle,
dependencies,
prefixCls: customizePrefixCls,
@ -119,6 +117,11 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
const prefixCls = getPrefixCls('form', customizePrefixCls);
// ========================= MISC =========================
// Get `noStyle` required info
const listContext = React.useContext(ListContext);
const fieldKeyPathRef = React.useRef<React.Key[]>();
// ======================== Errors ========================
// >>>>> Collect sub field errors
const [subFieldErrors, setSubFieldErrors] = useFrameState<Record<string, FieldError>>({});
@ -127,14 +130,27 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
const [meta, setMeta] = React.useState<Meta>(() => genEmptyMeta());
const onMetaChange = (nextMeta: Meta & { destroy?: boolean }) => {
// This keyInfo is not correct when field is removed
// Since origin keyManager no longer keep the origin key anymore
// Which means we need cache origin one and reuse when removed
const keyInfo = listContext?.getKey(nextMeta.name);
// Destroy will reset all the meta
setMeta(nextMeta.destroy ? genEmptyMeta() : nextMeta);
// Bump to parent since noStyle
if (noStyle && notifyParentMetaChange) {
let namePath = nextMeta.name;
if (fieldKey !== undefined) {
namePath = Array.isArray(fieldKey) ? fieldKey : [fieldKey!];
if (!nextMeta.destroy) {
if (keyInfo !== undefined) {
const [fieldKey, restPath] = keyInfo;
namePath = [fieldKey, ...restPath];
fieldKeyPathRef.current = namePath;
}
} else {
// Use origin cache data
namePath = fieldKeyPathRef.current || namePath;
}
notifyParentMetaChange(nextMeta, namePath);
}

View File

@ -8,7 +8,6 @@ import { FormItemPrefixContext } from './context';
export interface FormListFieldData {
name: number;
key: number;
fieldKey: number;
}
export interface FormListOperation {
@ -43,14 +42,10 @@ const FormList: React.FC<FormListProps> = ({
<List {...props}>
{(fields, operation, meta) => (
<FormItemPrefixContext.Provider value={{ prefixCls, status: 'error' }}>
{children(
fields.map(field => ({ ...field, fieldKey: field.key })),
operation,
{
{children(fields, operation, {
errors: meta.errors,
warnings: meta.warnings,
},
)}
})}
</FormItemPrefixContext.Provider>
)}
</List>

View File

@ -1904,6 +1904,112 @@ exports[`renders ./components/form/demo/dynamic-form-items-complex.md correctly
</form>
`;
exports[`renders ./components/form/demo/dynamic-form-items-no-style.md correctly 1`] = `
<form
autocomplete="off"
class="ant-form ant-form-horizontal"
id="dynamic_form_nest_item"
>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Users"
>
Users
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<button
class="ant-btn ant-btn-dashed ant-btn-block"
type="button"
>
<span
aria-label="plus"
class="anticon anticon-plus"
role="img"
>
<svg
aria-hidden="true"
data-icon="plus"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<defs />
<path
d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"
/>
<path
d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"
/>
</svg>
</span>
<span>
Add field
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
>
<span>
Submit
</span>
</button>
</div>
</div>
</div>
</div>
</form>
`;
exports[`renders ./components/form/demo/dynamic-rule.md correctly 1`] = `
<form
class="ant-form ant-form-horizontal"

View File

@ -23,7 +23,6 @@ describe('Form.List.NoStyle', () => {
<Form.Item
{...field}
name={[field.name, 'first']}
fieldKey={[field.fieldKey, 'first']}
rules={[{ required: true }]}
noStyle
>

View File

@ -61,7 +61,6 @@ const Demo = () => {
{...field}
label="Sight"
name={[field.name, 'sight']}
fieldKey={[field.fieldKey, 'sight']}
rules={[{ required: true, message: 'Missing sight' }]}
>
<Select disabled={!form.getFieldValue('area')} style={{ width: 130 }}>
@ -78,7 +77,6 @@ const Demo = () => {
{...field}
label="Price"
name={[field.name, 'price']}
fieldKey={[field.fieldKey, 'price']}
rules={[{ required: true, message: 'Missing price' }]}
>
<Input />

View File

@ -0,0 +1,66 @@
---
order: 4.11
title:
zh-CN: 动态增减嵌套纯字段
en-US: Dynamic Form nest pure Items
debug: true
---
## zh-CN
嵌套 `noStyle` 字段的动态表单示例。
## en-US
Nest with `noStyle` field dynamic form.
```jsx
import { Form, Input, Button, Space } from 'antd';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
const Demo = () => {
const onFinish = values => {
console.log('Received values of form:', values);
};
return (
<Form name="dynamic_form_nest_item" onFinish={onFinish} autoComplete="off">
<Form.Item label="Users">
<Form.List name="users">
{(fields, { add, remove }) => (
<>
{fields.map(field => (
<Space key={field.key} style={{ marginBottom: 16 }}>
<Form.Item noStyle name={[field.name, 'lastName']} rules={[{ required: true }]}>
<Input placeholder="Last Name" />
</Form.Item>
<Form.Item noStyle name={[field.name, 'firstName']} rules={[{ required: true }]}>
<Input placeholder="First Name" />
</Form.Item>
<MinusCircleOutlined
onClick={() => {
remove(field.name);
}}
/>
</Space>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
Add field
</Button>
</Form.Item>
</>
)}
</Form.List>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
ReactDOM.render(<Demo />, mountNode);
```

View File

@ -7,11 +7,11 @@ title:
## zh-CN
嵌套表单字段需要对 `field` 进行拓展,将 `field.name` `field.fieldKey` 应用于控制字段。
嵌套表单字段需要对 `field` 进行拓展,将 `field.name` 应用于控制字段。
## en-US
Nest dynamic field need extends `field`. Pass `field.name` and `field.fieldKey` to nest item.
Nest dynamic field need extends `field`. Pass `field.name` to nest item.
```jsx
import { Form, Input, Button, Space } from 'antd';
@ -27,12 +27,11 @@ const Demo = () => {
<Form.List name="users">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, fieldKey, ...restField }) => (
{fields.map(({ key, name, ...restField }) => (
<Space key={key} style={{ display: 'flex', marginBottom: 8 }} align="baseline">
<Form.Item
{...restField}
name={[name, 'first']}
fieldKey={[fieldKey, 'first']}
rules={[{ required: true, message: 'Missing first name' }]}
>
<Input placeholder="First Name" />
@ -40,7 +39,6 @@ const Demo = () => {
<Form.Item
{...restField}
name={[name, 'last']}
fieldKey={[fieldKey, 'last']}
rules={[{ required: true, message: 'Missing last name' }]}
>
<Input placeholder="Last Name" />

View File

@ -124,7 +124,7 @@
"rc-dialog": "~8.6.0",
"rc-drawer": "~4.4.2",
"rc-dropdown": "~3.2.0",
"rc-field-form": "~1.21.0",
"rc-field-form": "~1.22.0-2",
"rc-image": "~5.2.5",
"rc-input-number": "~7.3.0",
"rc-mentions": "~1.6.1",