What is rc-field-form?
The rc-field-form package is a React component library for managing form state and validation. It provides a set of tools to create complex forms with ease, including form validation, custom form controls, and form layout. It is designed to work with React's uncontrolled components and does not rely on external state management libraries.
What are rc-field-form's main functionalities?
Form and Field Components
Provides Form and Field components to create a form with validation rules. The Field component is used to define each form item with its validation rules.
{"<Form>
<Field name='username' rules={[{ required: true }]}/>
<Field name='password' rules={[{ required: true }]}/>
</Form>"}
Form Validation
Supports synchronous and asynchronous validation for form fields. The onFinish and onFinishFailed callbacks handle form submission and validation failure, respectively.
{"<Form onFinish={onFinish} onFinishFailed={onFinishFailed}>
<Field name='email' rules={[{ type: 'email', required: true }]}/>
<Field name='password' rules={[{ required: true }]}/>
<button type='submit'>Submit</button>
</Form>"}
Custom Form Controls
Allows the integration of custom form controls by using the render props pattern. The control object contains the necessary props for the custom input, and the meta object contains validation error messages.
{"<Form>
<Field name='customInput'>
{(control, meta) => <CustomInput {...control} error={meta.errors[0]} />}
</Field>
</Form>"}
Other packages similar to rc-field-form
formik
Formik is a popular form library for React that provides a similar set of functionalities as rc-field-form. It handles form state, validation, and submission. Formik is known for its simplicity and ease of use, but it might be more opinionated compared to rc-field-form.
react-hook-form
React Hook Form is another library for managing forms in React applications. It uses React hooks to manage form state and validation, aiming for better performance by minimizing re-renders. React Hook Form is often praised for its performance and simplicity compared to other form libraries.
redux-form
Redux Form integrates with Redux for form state management. It is a good choice for applications that already use Redux for state management. However, it might be heavier than rc-field-form and other alternatives because it relies on Redux.
rc-field-form
React Performance First Form Component.
Development
npm install
npm start
open http://localhost:9001/
Feature
Install
Usage
import Form, { Field } from 'rc-field-form';
<Form
onFinish={values => {
console.log('Finish:', values);
}}
>
<Field name="username">
<Input placeholder="Username" />
</Field>
<Field name="password">
<Input placeholder="Password" />
</Field>
<button>Submit</button>
</Form>;
export default Demo;
API
We use typescript to create the Type definition. You can view directly in IDE. But you can still check the type definition here.
Form
Prop | Description | Type | Default |
---|
fields | Control Form fields status. Only use when in Redux | FieldData[] | - |
form | Set form instance created by useForm | FormInstance | Form.useForm() |
initialValues | Initial value of Form | Object | - |
name | Config name with FormProvider | string | - |
validateMessages | Set validate message template | ValidateMessages | - |
onFieldsChange | Trigger when any value of Field changed | (changedFields, allFields): void | - |
onValuesChange | Trigger when any value of Field changed | (changedValues, values): void | - |
Field
Prop | Description | Type | Default |
---|
dependencies | Will re-render if dependencies changed | NamePath[] | - |
getValueFromEvent | Specify how to get value from event | (..args: any[]) => any | - |
name | Field name path | NamePath | - |
normalize | Normalize value before update | (value, prevValue, prevValues) => any | - |
rules | Validate rules | Rule[] | - |
shouldUpdate | Check if Field should update | (prevValues, nextValues): boolean | - |
trigger | Collect value update by event trigger | string | onChange |
validateTrigger | Config trigger point with rule validate | string | string[] | onChange |
List
Prop | Description | Type | Default |
---|
name | List field name path | NamePath[] | - |
children | Render props for listing fields | (fields: { name: NamePath }[], operations: ListOperations): ReactNode | - |
useForm
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.
const Demo = () => {
const [form] = Form.useForm();
return <Form form={form} />;
};
For class component user, you can use ref
to get form instance:
class Demo extends React.Component {
setRef = form => {
};
render() {
return <Form ref={this.setRef} />;
}
}
Prop | Description | Type |
---|
getFieldValue | Get field value by name path | (name: NamePath) => any |
getFieldsValue | Get list of field values by name path list | (nameList?: NamePath[]) => any |
getFieldError | Get field errors by name path | (name: NamePath) => string[] |
getFieldsError | Get list of field errors by name path list | (nameList?: NamePath[]) => FieldError[] |
isFieldsTouched | Check if list of fields are touched | (nameList?: NamePath[]) => boolean |
isFieldTouched | Check if a field is touched | (name: NamePath) => boolean |
isFieldValidating | Check if a field is validating | (name: NamePath) => boolean |
resetFields | Reset fields status | (fields?: NamePath[]) => void |
setFields | Set fields status | (fields: FieldData[]) => void |
setFieldsValue | Set fields value | (values) => void |
validateFields | Trigger fields to validate | (nameList?: NamePath[], options?: ValidateOptions) => Promise |
FormProvider
Prop | Description | Type | Default |
---|
validateMessages | Config global validateMessages template | ValidateMessages | - |
onFormChange | Trigger by named form fields change | (name, { changedFields, forms }) => void | - |
Interface
NamePath
Type |
---|
string | number | (string | number)[] |
FieldData
Prop | Type |
---|
touched | boolean |
validating | boolean |
errors | string[] |
name | string | number | (string | number)[] |
value | any |
Rule
Prop | Type |
---|
enum | any[] |
len | number |
max | number |
message | string |
min | number |
pattern | RegExp |
required | boolean |
transform | (value) => any |
type | string |
validator | (rule, value, callback: (error?: string) => void, form) => Promise | void |
whitespace | boolean |
validateTrigger | string | string[] |
validator
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.
ListOperations
Prop | Type |
---|
add | () => void |
remove | (index: number) => void |
ValidateMessages
Validate Messages provides a list of error template. You can ref here for fully default templates.
Prop | Description |
---|
enum | Rule enum prop |
len | Rule len prop |
max | Rule max prop |
min | Rule min prop |
name | Field name |
pattern | Rule pattern prop |
type | Rule type prop |
Different with rc-form
rc-field-form
is try to keep sync with rc-form
in api level, but there still have something to change:
🔥 Field will not keep snyc with initialValues
when un-touched
In rc-form
, field value will get from initialValues
if user not operate on it.
It's a bug but user use as a feature which makes fixing will be a breaking change and we have to keep it.
In Field Form, this bug will not exist anymore. If you want to change a field value, use setFieldsValue
instead.
🔥 Remove Field will not clean up related value
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.
🔥 Nest name use array instead of string
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.
Field Form will only trade ['user', 'name']
to be { user: { name: 'Bamboo' } }
, and user.name
to be { ['user.name']: 'Bamboo' }
.
🔥 Remove validateFieldsAndScroll
Since findDomNode
is marked as warning in StrictMode. It seems over control of Form component.
We decide to remove validateFieldsAndScroll
method and you should handle it with you own logic:
<Form>
<Field name="username">
<input ref={this.inputRef} />
</Field>
</Form>
🔥 getFieldsError
always return array
rc-form
returns null
when no error happen. This makes user have to do some additional code like:
(form.getFieldsError('fieldName') || []).forEach(() => {
});
Now getFieldsError
will return []
if no errors.
🔥 Remove callback
with validateFields
Since ES8 is support async/await
, that's no reason not to use it. Now you can easily handle your validate logic:
async function() {
try {
const values = await form.validateFields();
console.log(values);
} catch (errorList) {
errorList.forEach(({ name, errors }) => {
});
}
}
Notice: Now if your validator return an Error(message)
, not need to get error by e => e.message
. FieldForm will handle this.
🔥 preserve
is no need anymore
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.
🔥 setFields
not trigger onFieldsChange
and setFieldsValue
not trigger onValuesChange
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.
Additionally, user control update trigger onFieldsChange
& onValuesChange
event has potential dead loop risk.