Understanding rc-form: Internals, APIs, and Usage in React Forms
This article provides a comprehensive overview of rc-form, a React library used by Ant Design to manage form state, validation, and data collection, explaining why it is needed, its core APIs, practical usage examples, and a deep dive into its internal implementation.
rc-form is a lightweight library that Ant Design's Form component relies on to centralize form data management, validation, and value collection in React applications, eliminating the need for repetitive onChange handlers.
Why use rc-form? It creates a single data store (fieldsStore) that handles field registration, value updates, and validation, allowing developers to focus on UI logic while rc-form takes care of the boilerplate.
Main APIs
Api Name
Description
Type
getFieldDecorator
Wraps a field component for two‑way binding
Function(name)
getFieldsValue
Returns values of a set of fields (optionally all)
(nameList?: NamePath[], filterFunc?: (meta) => boolean) => any
getFieldValue
Gets the value of a specific field
(name: NamePath) => any
setFieldsValue
Sets values for multiple fields
(values) => void
setFields
Updates the status of a group of fields
(fields: FieldData[]) => void
validateFields
Triggers validation for specified fields
(nameList?: NamePath[]) => Promise
isFieldValidating
Checks whether a field is currently validating
(name: NamePath) => boolean
getFieldProps
Generates the props that should be spread onto a field component
(name: NamePath) => any
Basic usage example
import React, { Component } from "react";
export default class index extends Component {
state = { value1: "peter", value2: "123", value3: "23" };
onChange1 = ({ target: { value } }) => { this.setState({ value1: value }); };
onChange2 = ({ target: { value } }) => { this.setState({ value2: value }); };
onChange3 = ({ target: { value } }) => { this.setState({ value3: value }); };
submit = async () => {
const { value1, value2, value3 } = this.state;
const obj = { value1, value2, value3 };
const res = await axios("url", obj);
};
render() {
const { value1, value2, value3 } = this.state;
return (
用户名:
密码:
年龄:
提交
);
}
}When the form grows, writing dozens of onChange handlers becomes unwieldy; rc-form solves this by providing createForm (a higher‑order component) that injects a form prop with the APIs above.
Using rc-form with Ant Design
import { createForm } from "../../rc-form";
const RcForm = (props) => {
const { form: { getFieldDecorator, validateFields } } = props;
const handleSubmit = (e) => {
e && e.stopPropagation();
validateFields((err, value) => {
if (!err) {
console.log(value);
}
});
};
return (
姓名:
{getFieldDecorator("username", {
rules: [{ required: true, message: "请输入用户名!" }],
initialValue: 'initialValue',
})(
)}
密码:
{getFieldDecorator("password", {
rules: [
{ required: true, message: "请输入密码!" },
{ pattern: /^[a-z0-9_-]{6,18}$/, message: '只允许数字!' },
],
})(
)}
提交
);
};
export default createForm()(RcForm);Internal implementation highlights
getFieldDecorator(name, fieldOption) registers the field, retrieves its meta data from fieldsStore , and returns a function that clones the original component with the generated props and value bindings.
getFieldProps(name, usersFieldOption = {}) {
const fieldOption = {
name,
trigger: DEFAULT_TRIGGER,
valuePropName: 'value',
validate: [],
...usersFieldOption,
};
const { rules, trigger, validateTrigger = trigger, validate } = fieldOption;
const fieldMeta = this.fieldsStore.getFieldMeta(name);
if ('initialValue' in fieldOption) {
fieldMeta.initialValue = fieldOption.initialValue;
}
const inputProps = {
...this.fieldsStore.getFieldValuePropValue(fieldOption),
ref: this.getCacheBind(name, `${name}__ref`, this.saveRef),
};
// bind validation triggers
const validateRules = normalizeValidateRules(validate, rules, validateTrigger);
const validateTriggers = getValidateTriggers(validateRules);
validateTriggers.forEach(action => {
if (inputProps[action]) return;
inputProps[action] = this.getCacheBind(name, action, this.onCollectValidate);
});
if (trigger && validateTriggers.indexOf(trigger) === -1) {
inputProps[trigger] = this.getCacheBind(name, trigger, this.onCollect);
}
return inputProps;
}The fieldsStore object holds two maps: fieldsMeta (static configuration such as rules, triggers, and original props) and fields (dynamic state like value , dirty , errors , validating ). Methods like getFieldMeta , setFields , and validateFieldsInternal manipulate these structures.
onCollectValidate(name_, action, ...args) {
const { field, fieldMeta } = this.onCollectCommon(name_, action, args);
const newField = { ...field, dirty: true };
this.fieldsStore.setFieldsAsDirty();
this.validateFieldsInternal([newField], { action, options: { firstFields: !!fieldMeta.validateFirst } });
}When a validation‑triggering event occurs, onCollectValidate marks the field dirty, runs the async validator, and updates the store with any errors. For non‑validation events, onCollect simply updates the value and forces a re‑render.
Overall design
createForm(options) is a thin wrapper around createBaseForm , which returns a higher‑order component. This HOC injects a form prop into the wrapped component, granting access to all rc‑form APIs. The injected form object interacts with fieldsStore to keep the UI in sync with the underlying data model.
Conclusion
rc-form provides a robust solution for managing complex form state and validation in React, but developers should be aware of potential re‑render performance costs; for high‑performance scenarios, the newer rc-field-form library may be a better fit.
政采云技术
ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.