mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-16 01:41:02 +08:00
293 lines
6.7 KiB
Markdown
293 lines
6.7 KiB
Markdown
---
|
|
title: Migrate to v4
|
|
skip: true
|
|
---
|
|
|
|
### Remove Form.create
|
|
|
|
Form of v4 is not need create context by `Form.create()`. Form is now have own data scope and you don't need `getFieldDecorator` anymore. Just use Form.Item directly:
|
|
|
|
```jsx
|
|
// antd v3
|
|
const Demo = ({ form: { getFieldDecorator } }) => (
|
|
<Form>
|
|
<Form.Item>
|
|
{getFieldDecorator('username', {
|
|
rules: [{ required: true }],
|
|
})(<Input />)}
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
|
|
const WrappedDemo = Form.create()(Demo);
|
|
```
|
|
|
|
To:
|
|
|
|
```jsx
|
|
// antd v4
|
|
const Demo = () => (
|
|
<Form>
|
|
<Form.Item name="username" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
```
|
|
|
|
Since `Form.create()` is removed, origin `onFieldsChange` or other methods moved to Form, and control by `fields`. ref [example](/components/form/#components-form-demo-global-state)。
|
|
|
|
### Form control
|
|
|
|
If you want to control form, you can use `Form.useForm()` to create Form instance for operation:
|
|
|
|
```jsx
|
|
// antd v3
|
|
const Demo = ({ form: { setFieldsValue } }) => {
|
|
React.useEffect(() => {
|
|
setFieldsValue({
|
|
username: 'Bamboo',
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<Form>
|
|
<Form.Item>
|
|
{getFieldDecorator('username', {
|
|
rules: [{ required: true }],
|
|
})(<Input />)}
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
};
|
|
|
|
const WrappedDemo = Form.create()(Demo);
|
|
```
|
|
|
|
To:
|
|
|
|
```jsx
|
|
// antd v4
|
|
const Demo = () => {
|
|
const [form] = Form.useForm();
|
|
|
|
React.useEffect(() => {
|
|
form.setFieldsValue({
|
|
username: 'Bamboo',
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<Form form={form}>
|
|
<Form.Item name="username" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
};
|
|
```
|
|
|
|
For class component, you can use `ref` to access instance:
|
|
|
|
```jsx
|
|
// antd v4
|
|
class Demo extends React.Component {
|
|
formRef = React.createRef();
|
|
|
|
componentDidMount() {
|
|
this.formRef.setFieldsValue({
|
|
username: 'Bamboo',
|
|
});
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<Form ref={formRef}>
|
|
<Form.Item name="username" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
If you don't want to use the Item style, you can use `inline` prop to remove it:
|
|
|
|
```jsx
|
|
// antd v3
|
|
const Demo = ({ form: { setFieldsValue } }) => {
|
|
return <Form>{getFieldDecorator('username')(<Input />)}</Form>;
|
|
};
|
|
|
|
const WrappedDemo = Form.create()(Demo);
|
|
```
|
|
|
|
To:
|
|
|
|
```jsx
|
|
// antd v4
|
|
const Demo = () => {
|
|
return (
|
|
<Form>
|
|
<Form.Item name="username" noStyle>
|
|
<Input />
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
};
|
|
```
|
|
|
|
### Linkage with field
|
|
|
|
New Form use incremental update which only update related field. So if there are some linkage between fields or update with whole form. You can use [`dependencies`](/components/form/#dependencies) or [`shouldUpdate`](/components/form/#shouldUpdate) to handle that.
|
|
|
|
### replace onSubmit with onFinish
|
|
|
|
You need to listen `onSubmit` and call `validateFields` to handle validation in old Form. New Form provides `onFinish` which only trigger when validation is passed:
|
|
|
|
```jsx
|
|
// antd v3
|
|
const Demo = ({ form: { getFieldDecorator, validateFields } }) => {
|
|
const onSubmit = e => {
|
|
e.preventDefault();
|
|
validateFields((err, values) => {
|
|
if (!err) {
|
|
console.log('Received values of form: ', values);
|
|
}
|
|
});
|
|
};
|
|
|
|
return (
|
|
<Form onSubmit={onSubmit}>
|
|
<Form.Item>
|
|
{getFieldDecorator('username', {
|
|
rules: [{ required: true }],
|
|
})(<Input />)}
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
};
|
|
|
|
const WrappedDemo = Form.create()(Demo);
|
|
```
|
|
|
|
To:
|
|
|
|
```jsx
|
|
// antd v4
|
|
const Demo = () => {
|
|
const onFinish = values => {
|
|
console.log('Received values of form: ', values);
|
|
};
|
|
|
|
return (
|
|
<Form onFinish={onFinish}>
|
|
<Form.Item name="username" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
};
|
|
```
|
|
|
|
## Replace validateFieldsAndScroll with scrollToField
|
|
|
|
New version recommend use `onFinish` for submit after validation. Thus `validateFieldsAndScroll` is change to more flexible method `scrollToField`:
|
|
|
|
```jsx
|
|
// antd v3
|
|
onSubmit = () => {
|
|
form.validateFieldsAndScroll((error, values) => {
|
|
// Your logic
|
|
});
|
|
};
|
|
```
|
|
|
|
To:
|
|
|
|
```jsx
|
|
// antd v4
|
|
onFinishFailed = ({ errorFields }) => {
|
|
form.scrollToField(errorFields[0].name);
|
|
};
|
|
```
|
|
|
|
### Initialization
|
|
|
|
Besides, we move `initialValue` into Form to avoid field with same name both using `initialValue` to cause conflict:
|
|
|
|
```jsx
|
|
// antd v3
|
|
const Demo = ({ form: { getFieldDecorator } }) => (
|
|
<Form>
|
|
<Form.Item>
|
|
{getFieldDecorator('username', {
|
|
rules: [{ required: true }],
|
|
initialValue: 'Bamboo',
|
|
})(<Input />)}
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
|
|
const WrappedDemo = Form.create()(Demo);
|
|
```
|
|
|
|
To:
|
|
|
|
```jsx
|
|
// antd v4
|
|
const Demo = () => (
|
|
<Form initialValues={{ username: 'Bamboo' }}>
|
|
<Form.Item name="username" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
```
|
|
|
|
In v3, modifying the `initialValue` of un-operated field will update the field value synchronously, which is a bug. However, since it has been used as a feature for a long time, we have not fixed it. In v4, the bug has been fixed. `initialValues` only takes effect when initializing and resetting the form.
|
|
|
|
### Remove field no longer removes field value
|
|
|
|
In v3, we will clean up the values when the fields removed. However, it has been found that clearing fields can cause greater inconvenience than retention in practice. For example like some switching operations, the user has to retain the field value in a hidden way. Therefore, the new version of Form will always keep the fields value, and the validation rules for removing field will be ignored. So `preserve` is no longer needed.
|
|
|
|
### Nested field paths using arrays
|
|
|
|
In the past versions we used `.` to represent nested paths (such as `user.name` to represent `{ user: { name: '' } }`). However, in some backend systems, `.` is also included in the variable name. This causes the user to need additional code to convert, so in the new version, nested paths are represented by arrays to avoid unexpected behavior (eg `['user', 'name']`).
|
|
|
|
Therefore, paths returned by methods such as `getFieldsError` are always in an array form for the user to handle:
|
|
|
|
```jsx
|
|
form.getFieldsError();
|
|
|
|
/*
|
|
[
|
|
{ name: ['user', 'name'], errors: [] },
|
|
{ name: ['user', 'age'], errors: ['Some error message'] },
|
|
]
|
|
*/
|
|
```
|
|
|
|
### Remove callback in validateFields
|
|
|
|
`validateFields` will return a Promise, so you can handle the error with `async/await` or `then/catch`. It is no longer necessary to determine if `errors` is empty:
|
|
|
|
```jsx
|
|
// antd v3
|
|
validateFields((err, value) => {
|
|
if (!err) {
|
|
// Do something with value
|
|
}
|
|
});
|
|
```
|
|
|
|
To
|
|
|
|
```jsx
|
|
// antd v4
|
|
validateFields().then(values => {
|
|
// Do something with value
|
|
});
|
|
```
|