Mastering Form Architecture: Principles, Best Practices, and Design Patterns in Frontend Development
This article explains how a single Form instance centrally manages form data, uses subscription and notification mechanisms to update components, and demonstrates the Observer and Singleton design patterns with concrete React code examples for building efficient, maintainable frontend forms.
Preface
Form principles and best practices to improve daily development efficiency.
Design patterns used in Form source code to enrich your coding toolbox.
Principles
In a word: At the data layer, a single instance uniformly manages all form data, updates via event subscription and notification, and triggers component re‑render on changes.
Form and Item
Single Instance
Each Form component has an associated instance object that centralizes form state, validation rules, etc. The most common usage is: const [form] = Form.useForm(); This creates a form instance containing a state store and methods for CRUD operations as well as event subscription and notification.
Subscription and Notification
Two simplified code snippets illustrate the core mechanism:
private fieldEntities = [];
// Register Item instance in Form instance
private registerField = (entity) => {
// Store child instance
this.fieldEntities.push(entity);
...
}
// Notify Items
private notifyObservers = (...args) => {
...
this.getFieldEntities().forEach(({ onStoreChange }) => {
onStoreChange(...);
});
...
}; class Field extends ... {
public componentDidMount() {
...
// Item registers itself to the form instance
this.cancelRegisterFunc = registerField(this);
...
}
// Callback provided to the form instance for notifications
public onStoreChange = (prevStore, namePathList, info) => {
...
switch (info.type) {
case 'reset':
...
break;
case 'remove':
...
break;
case 'setField':
this.reRender();
...
break;
case 'dependenciesUpdate':
...
break;
default:
...
break;
}
...
};
// Re‑render the Item component
public reRender() {
...
this.forceUpdate();
}
}When the form instance’s state changes, it iterates over Item instances’ onStoreChange methods, causing each Item component to update.
Item components obtain the form instance via React Context and useContext, allowing them to call registerField and register themselves.
Item and Controlled Components
Custom or generic controlled components follow the convention: const { value, onChange, ... } = props; The value is rendered, and changes are sent back via the onChange callback.
value
public getValue = (...) => {
const { getFieldsValue }: FormInstance = this.props.context;
const namePath = this.getNamePath();
...
};onChange
// Usage
onChange = (...args) => {
...
dispatch({
type: 'updateValue',
namePath,
value: newValue,
});
...
};
private dispatch = (action) => {
switch (action.type) {
case 'updateValue': {
const { namePath, value } = action;
this.updateValue(namePath, value);
break;
}
default:
// Currently we don't have other action. Do nothing.
}
};
private updateValue = (name, value) => {
const namePath = getNamePath(name);
const prevStore = this.store;
this.updateStore(setValue(this.store, namePath, value));
this.notifyObservers(prevStore, [namePath], {
type: 'valueUpdate',
source: 'internal',
});
...
};When an Item’s value changes, the form store updates, dependency checks run, observers are notified, and the new value and onChange are injected into child component props, completing the loop.
Design Patterns in Source Code
Observer Pattern
The Observer pattern establishes a one‑to‑many dependency: when an object’s state changes, all dependent objects are notified and automatically updated.
Complex backend editing forms often require inter‑field linkage; using the Form’s built‑in observer architecture simplifies such interactions.
Beyond forms, scenarios like a shopping cart can benefit: multiple components depend on a shared data store, and any change triggers unified notifications to update UI and synchronize with the backend.
Singleton Pattern
function useForm<Values = any>(form?: FormInstance<Values>): [FormInstance<Values>] {
const formRef = React.useRef<FormInstance>();
...
if (!formRef.current) {
if (form) {
formRef.current = form;
} else {
...
const formStore: FormStore = new FormStore(forceReRender);
formRef.current = formStore.getForm();
}
}
...
return [formRef.current];
}The useForm hook ensures a single form state instance, preventing conflicts between multiple instances.
Combining Singleton with Observer allows a globally unique data store to be observed by many components, providing a maintainable and decoupled architecture.
Conclusion
In mid‑backend development, forms are indispensable; leveraging their underlying design patterns helps organize code structure effectively.
Understanding the abstracted design patterns beyond the form’s implementation equips you with versatile tools for future projects.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Goodme Frontend Team
Regularly sharing the team's insights and expertise in the frontend field
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.
