1 | # rc-field-form
|
2 |
|
3 | React Performance First Form Component.
|
4 |
|
5 | [![NPM version][npm-image]][npm-url] [![dumi](https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square)](https://github.com/umijs/dumi) [![build status][github-actions-image]][github-actions-url] [![Codecov][codecov-image]][codecov-url] [![npm download][download-image]][download-url]
|
6 |
|
7 | [npm-image]: http://img.shields.io/npm/v/rc-field-form.svg?style=flat-square
|
8 | [npm-url]: http://npmjs.org/package/rc-field-form
|
9 | [github-actions-image]: https://github.com/react-component/field-form/workflows/CI/badge.svg
|
10 | [github-actions-url]: https://github.com/react-component/field-form/actions
|
11 | [codecov-image]: https://img.shields.io/codecov/c/github/react-component/field-form/master.svg?style=flat-square
|
12 | [codecov-url]: https://codecov.io/gh/react-component/field-form/branch/master
|
13 | [download-image]: https://img.shields.io/npm/dm/rc-field-form.svg?style=flat-square
|
14 | [download-url]: https://npmjs.org/package/rc-field-form
|
15 |
|
16 | ## Development
|
17 |
|
18 | ```bash
|
19 | npm install
|
20 | npm start
|
21 | open http://localhost:8000
|
22 | ```
|
23 |
|
24 | ## Feature
|
25 |
|
26 | - Support react.js and even react-native
|
27 | - Validate fields with [async-validator](https://github.com/yiminghe/async-validator/)
|
28 |
|
29 | ## Install
|
30 |
|
31 | [![rc-field-form](https://nodei.co/npm/rc-field-form.png)](https://npmjs.org/package/rc-field-form)
|
32 |
|
33 | ## Usage
|
34 |
|
35 | ```js | pure
|
36 | import Form, { Field } from 'rc-field-form';
|
37 |
|
38 | const Input = ({ value = "", ...props }) => <input value={value} {...props} />;
|
39 |
|
40 | const Demo = () => {
|
41 | return (
|
42 | <Form
|
43 | onFinish={(values) => {
|
44 | console.log("Finish:", values);
|
45 | }}
|
46 | >
|
47 | <Field name="username">
|
48 | <Input placeholder="Username" />
|
49 | </Field>
|
50 | <Field name="password">
|
51 | <Input placeholder="Password" />
|
52 | </Field>
|
53 |
|
54 | <button>Submit</button>
|
55 | </Form>
|
56 | );
|
57 | };
|
58 |
|
59 | export default Demo;
|
60 | ```
|
61 |
|
62 | ## 🔥 API
|
63 |
|
64 | We use typescript to create the Type definition. You can view directly in IDE. But you can still check the type definition [here](https://github.com/react-component/field-form/blob/master/src/interface.ts).
|
65 |
|
66 | ### Form
|
67 |
|
68 | | Prop | Description | Type | Default |
|
69 | | ---------------- | -------------------------------------------------- | -------------------------------------------- | ---------------- |
|
70 | | component | Customize Form render component | string \| Component \| false | form |
|
71 | | fields | Control Form fields status. Only use when in Redux | [FieldData](#fielddata)[] | - |
|
72 | | form | Set form instance created by `useForm` | [FormInstance](#useform) | `Form.useForm()` |
|
73 | | initialValues | Initial value of Form | Object | - |
|
74 | | name | Config name with [FormProvider](#formprovider) | string | - |
|
75 | | preserve | Preserve value when field removed | boolean | false |
|
76 | | validateMessages | Set validate message template | [ValidateMessages](#validatemessages) | - |
|
77 | | onFieldsChange | Trigger when any value of Field changed | (changedFields, allFields) => void | - |
|
78 | | onFinish | Trigger when form submit and success | (values) => void | - |
|
79 | | onFinishFailed | Trigger when form submit and failed | ({ values, errorFields, outOfDate }) => void | - |
|
80 | | onValuesChange | Trigger when any value of Field changed | (changedValues, values) => void | - |
|
81 |
|
82 | ### Field
|
83 |
|
84 | | Prop | Description | Type | Default |
|
85 | | ----------------- | ----------------------------------------------------------------------------- | ------------------------------------------- | -------- |
|
86 | | dependencies | Will re-render if dependencies changed | [NamePath](#namepath)[] | - |
|
87 | | getValueFromEvent | Specify how to get value from event | (..args: any[]) => any | - |
|
88 | | getValueProps | Customize additional props with value. This prop will disable `valuePropName` | (value) => any | - |
|
89 | | initialValue | Field initial value | any | - |
|
90 | | name | Field name path | [NamePath](#namepath) | - |
|
91 | | normalize | Normalize value before update | (value, prevValue, prevValues) => any | - |
|
92 | | preserve | Preserve value when field removed | boolean | false |
|
93 | | rules | Validate rules | [Rule](#rule)[] | - |
|
94 | | shouldUpdate | Check if Field should update | boolean \| (prevValues, nextValues) => boolean | - |
|
95 | | trigger | Collect value update by event trigger | string | onChange |
|
96 | | validateTrigger | Config trigger point with rule validate | string \| string[] | onChange |
|
97 | | valuePropName | Config value mapping prop with element | string | value |
|
98 |
|
99 | ### List
|
100 |
|
101 | | Prop | Description | Type | Default |
|
102 | | -------- | ------------------------------- | ------------------------------------------------------------------------------------------------------- | ------- |
|
103 | | name | List field name path | [NamePath](#namepath)[] | - |
|
104 | | children | Render props for listing fields | (fields: { name: [NamePath](#namepath) }[], operations: [ListOperations](#listoperations)) => ReactNode | - |
|
105 |
|
106 | ### useForm
|
107 |
|
108 | Form component default create an form instance by `Form.useForm`. But you can create it and pass to Form also. This allow you to call some function on the form instance.
|
109 |
|
110 | ```jsx | pure
|
111 | const Demo = () => {
|
112 | const [form] = Form.useForm();
|
113 | return <Form form={form} />;
|
114 | };
|
115 | ```
|
116 |
|
117 | For class component user, you can use `ref` to get form instance:
|
118 |
|
119 | ```jsx | pure
|
120 | class Demo extends React.Component {
|
121 | setRef = form => {
|
122 | // Form instance here
|
123 | };
|
124 |
|
125 | render() {
|
126 | return <Form ref={this.setRef} />;
|
127 | }
|
128 | }
|
129 | ```
|
130 |
|
131 | | Prop | Description | Type |
|
132 | | ----------------- | ------------------------------------------ | -------------------------------------------------------------------------- |
|
133 | | getFieldValue | Get field value by name path | (name: [NamePath](#namepath)) => any |
|
134 | | getFieldsValue | Get list of field values by name path list | (nameList?: ([NamePath](#namepath)[]) => any) \| true |
|
135 | | getFieldError | Get field errors by name path | (name: [NamePath](#namepath)) => string[] |
|
136 | | getFieldsError | Get list of field errors by name path list | (nameList?: [NamePath](#namepath)[]) => FieldError[] |
|
137 | | isFieldsTouched | Check if list of fields are touched | (nameList?: [NamePath](#namepath)[], allTouched?: boolean) => boolean |
|
138 | | isFieldTouched | Check if a field is touched | (name: [NamePath](#namepath)) => boolean |
|
139 | | isFieldValidating | Check if a field is validating | (name: [NamePath](#namepath)) => boolean |
|
140 | | resetFields | Reset fields status | (fields?: [NamePath](#namepath)[]) => void |
|
141 | | setFields | Set fields status | (fields: FieldData[]) => void |
|
142 | | setFieldsValue | Set fields value | (values) => void |
|
143 | | submit | Trigger form submit | () => void |
|
144 | | validateFields | Trigger fields to validate | (nameList?: [NamePath](#namepath)[], options?: ValidateOptions) => Promise |
|
145 |
|
146 | ### FormProvider
|
147 |
|
148 | | Prop | Description | Type | Default |
|
149 | | ---------------- | ----------------------------------------- | ---------------------------------------- | ------- |
|
150 | | validateMessages | Config global `validateMessages` template | [ValidateMessages](#validatemessages) | - |
|
151 | | onFormChange | Trigger by named form fields change | (name, { changedFields, forms }) => void | - |
|
152 | | onFormFinish | Trigger by named form fields finish | (name, { values, forms }) => void | - |
|
153 |
|
154 | ## 📋 Interface
|
155 |
|
156 | ### NamePath
|
157 |
|
158 | | Type |
|
159 | | ---------------------------------------- |
|
160 | | string \| number \| (string \| number)[] |
|
161 |
|
162 | ### FieldData
|
163 |
|
164 | | Prop | Type |
|
165 | | ---------- | ---------------------------------------- |
|
166 | | touched | boolean |
|
167 | | validating | boolean |
|
168 | | errors | string[] |
|
169 | | name | string \| number \| (string \| number)[] |
|
170 | | value | any |
|
171 |
|
172 | ### Rule
|
173 |
|
174 | | Prop | Type |
|
175 | | --------------- | ----------------------------------------------------------------------------------------------- |
|
176 | | enum | any[] |
|
177 | | len | number |
|
178 | | max | number |
|
179 | | message | string |
|
180 | | min | number |
|
181 | | pattern | RegExp |
|
182 | | required | boolean |
|
183 | | transform | (value) => any |
|
184 | | type | string |
|
185 | | validator | ([rule](#rule), value, callback: (error?: string) => void, [form](#useform)) => Promise \| void |
|
186 | | whitespace | boolean |
|
187 | | validateTrigger | string \| string[] |
|
188 |
|
189 | #### validator
|
190 |
|
191 | To keep sync with `rc-form` legacy usage of `validator`, we still provides `callback` to trigger validate finished. But in `rc-field-form`, we strongly recommend to return a Promise instead.
|
192 |
|
193 | ### ListOperations
|
194 |
|
195 | | Prop | Type |
|
196 | | ------ | ------------------------ |
|
197 | | add | (initValue: any) => void |
|
198 | | remove | (index: number) => void |
|
199 |
|
200 | ### ValidateMessages
|
201 |
|
202 | Validate Messages provides a list of error template. You can ref [here](https://github.com/react-component/field-form/blob/master/src/utils/messages.ts) for fully default templates.
|
203 |
|
204 | | Prop | Description |
|
205 | | ------- | ------------------- |
|
206 | | enum | Rule `enum` prop |
|
207 | | len | Rule `len` prop |
|
208 | | max | Rule `max` prop |
|
209 | | min | Rule `min` prop |
|
210 | | name | Field name |
|
211 | | pattern | Rule `pattern` prop |
|
212 | | type | Rule `type` prop |
|
213 |
|
214 | ## Different with `rc-form`
|
215 |
|
216 | `rc-field-form` is try to keep sync with `rc-form` in api level, but there still have something to change:
|
217 |
|
218 | ### 1. Field will not keep snyc with `initialValues` when un-touched
|
219 |
|
220 | In `rc-form`, field value will get from `initialValues` if user not operate on it.
|
221 | It's a bug but user use as a feature which makes fixing will be a breaking change and we have to keep it.
|
222 | In Field Form, this bug will not exist anymore. If you want to change a field value, use `setFieldsValue` instead.
|
223 |
|
224 | ### 2. Remove Field will not clean up related value
|
225 |
|
226 | We do lots of logic to clean up the value when Field removed before. But with user feedback, remove exist value increase the additional work to keep value back with conditional field.
|
227 |
|
228 | ### 3. Nest name use array instead of string
|
229 |
|
230 | In `rc-form`, we support like `user.name` to be a name and convert value to `{ user: { name: 'Bamboo' } }`. This makes '.' always be the route of variable, this makes developer have to do additional work if name is real contains a point like `app.config.start` to be `app_config_start` and parse back to point when submit.
|
231 |
|
232 | Field Form will only trade `['user', 'name']` to be `{ user: { name: 'Bamboo' } }`, and `user.name` to be `{ ['user.name']: 'Bamboo' }`.
|
233 |
|
234 | ### 4. Remove `validateFieldsAndScroll`
|
235 |
|
236 | Since `findDomNode` is marked as warning in [StrictMode](https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage). It seems over control of Form component.
|
237 | We decide to remove `validateFieldsAndScroll` method and you should handle it with you own logic:
|
238 |
|
239 | ```jsx | pure
|
240 | <Form>
|
241 | <Field name="username">
|
242 | <input ref={this.inputRef} />
|
243 | </Field>
|
244 | </Form>
|
245 | ```
|
246 |
|
247 | ### 5. `getFieldsError` always return array
|
248 |
|
249 | `rc-form` returns `null` when no error happen. This makes user have to do some additional code like:
|
250 |
|
251 | ```js | pure
|
252 | (form.getFieldsError('fieldName') || []).forEach(() => {
|
253 | // Do something...
|
254 | });
|
255 | ```
|
256 |
|
257 | Now `getFieldsError` will return `[]` if no errors.
|
258 |
|
259 | ### 6. Remove `callback` with `validateFields`
|
260 |
|
261 | Since ES8 is support `async/await`, that's no reason not to use it. Now you can easily handle your validate logic:
|
262 |
|
263 | ```js | pure
|
264 | async function() {
|
265 | try {
|
266 | const values = await form.validateFields();
|
267 | console.log(values);
|
268 | } catch (errorList) {
|
269 | errorList.forEach(({ name, errors }) => {
|
270 | // Do something...
|
271 | });
|
272 | }
|
273 | }
|
274 | ```
|
275 |
|
276 | **Notice: Now if your validator return an `Error(message)`, not need to get error by `e => e.message`. FieldForm will handle this.**
|
277 |
|
278 | ### 7. `preserve` is default to false
|
279 |
|
280 | In `rc-form` you should use `preserve` to keep a value cause Form will auto remove a value from Field removed. Field Form will always keep the value in the Form whatever Field removed. But you can still use `preserve=false` to disable value keeping since `1.5.0`.
|
281 |
|
282 | ### 8. `setFields` not trigger `onFieldsChange` and `setFieldsValue` not trigger `onValuesChange`
|
283 |
|
284 | In `rc-form`, we hope to help user auto trigger change event by setting to make redux dispatch easier, but it's not good design since it makes code logic couping.
|
285 |
|
286 | Additionally, user control update trigger `onFieldsChange` & `onValuesChange` event has potential dead loop risk.
|