How to Manage State for Individual Fields in Formily: A Complete Guide
Formily provides the form.setFieldState() and form.getFieldState() APIs to declaratively mutate and read the UI state of any field using patterns, query objects, or direct field references.
Managing state for individual fields in Formily is handled through the Form model's batch state APIs, which allow you to target specific fields or groups using flexible matching patterns. Whether you need to toggle visibility, update values, or read validation status, Formily's state management layer—implemented in @formily/core—provides a type-safe and reactive solution.
Understanding Field State Architecture
The Field State Object (IGeneralFieldState)
Formily stores every aspect of a field's UI state—its value, visibility, validation status, and more—inside a field state object. According to the source code in packages/core/src/types.ts, this state is typed as IGeneralFieldState, which combines IFieldState (for data fields) and IVoidFieldState (for void fields)【5†L93-L95】.
When you interact with field state, you are either reading from or writing to this structured object, which includes properties like value, visible, disabled, readOnly, and errors.
Core APIs for State Management
The Form class in packages/core/src/models/Form.ts exposes two primary methods for managing field state:
form.setFieldState(pattern, setter)– Mutates the state of one or many fields using a callback function or partial state object.form.getFieldState(pattern, getter?)– Reads the state of a field, optionally applying a selector function to extract specific values.
Both methods accept a field-match pattern, which can be a string path, a FormPathPattern, a Query object, or an actual field instance【5†L87-L89】. Internally, these methods delegate to the batch state utilities defined in packages/core/src/shared/internals.ts—specifically createBatchStateSetter and createBatchStateGetter【6†L71-L90】.
How to Set Field State in Formily
Updating a Single Field
To modify a specific field, pass its path as the first argument to form.setFieldState(). The second argument can be a callback that receives the current state object, or a plain partial state object.
When the pattern resolves to a single field, Formily invokes the field's own setState method, which is created via createStateSetter(this) in packages/core/src/models/Field.ts【9†L57-L60】.
import { createForm } from '@formily/core';
const form = createForm();
// Using a callback to hide a field and set a default value
form.setFieldState('username', state => {
state.visible = false;
state.value = 'guest';
});
Alternatively, pass a partial state object directly:
// Direct partial update
form.setFieldState('age', { value: 30, disabled: true });
The batch setter in internals.ts detects plain objects and forwards them to field.setState【6†L73-L80】.
Batch Updates with Wildcard Patterns
You can target multiple fields simultaneously using wildcard patterns. Formily parses the pattern using FormPath, queries for matching fields via form.query(), and applies the payload to each result【6†L80-L86】.
// Set all fields under "address" to read-only
form.setFieldState('address.*', { readOnly: true });
If no fields currently match the pattern and the pattern is a wildcard, Formily registers a subscription so that future fields matching the pattern will automatically receive the payload when they are created. This logic is handled by subscribeUpdate in internals.ts【6†L86-L90】.
Using Query Objects for Complex Selections
For advanced filtering, create a Query object and pass it directly to setFieldState. The Query class implements the FieldMatchPattern interface, making it compatible with the batch setter without additional parsing.
// Select only required fields
const requiredFields = form.query('*').filter(field => field.required);
// Disable all required fields
form.setFieldState(requiredFields, { disabled: true });
Formily uses helper predicates like isQuery and isGeneralField from packages/core/src/shared/checkers.ts to determine how to process the pattern argument【6†L71-L75】.
How to Read Field State in Formily
Reading Values with Selectors
Use form.getFieldState() to extract specific values by providing a selector callback as the second argument. This avoids returning the entire state object when you only need one property.
const age = form.getFieldState('age', state => state.value);
console.log('Current age:', age);
Retrieving Complete State Objects
Omit the selector function to retrieve the full field state object. This returns the raw IGeneralFieldState containing all UI and data properties.
const usernameState = form.getFieldState('username');
console.log(usernameState);
// { value: 'guest', visible: false, disabled: false, ... }
When the pattern matches multiple fields, getFieldState returns an array of state objects or selected values. The batch getter logic in internals.ts handles both single and multiple match scenarios, iterating over query results and aggregating the return values【6†L71-L90】.
Summary
- Formily manages field state through the
IGeneralFieldStatetype, which combines data-field and void-field properties inpackages/core/src/types.ts. - Use
form.setFieldState()to mutate state via patterns, accepting callbacks or partial objects. Internally, this delegates tocreateBatchStateSetterininternals.ts. - Use
form.getFieldState()to read state with optional selectors, implemented viacreateBatchStateGetter. - Pattern matching supports strings,
FormPathPattern,Queryobjects, and field instances, with wildcard support for batch operations. - Lazy subscriptions ensure that state updates apply to fields created after the initial call when using wildcard patterns.
Frequently Asked Questions
How do I update multiple fields at once in Formily?
Pass a wildcard pattern (e.g., 'address.*') or a Query object to form.setFieldState(). Formily will resolve all matching fields using form.query() and apply the state mutation to each one. If fields don't exist yet, the framework registers a subscription to apply the update when matching fields are created later.
What is the difference between setFieldState and a field's setState method?
form.setFieldState() is a batch operation that accepts patterns and can target multiple fields, delegating to individual field.setState() calls. The field's setState method—defined in packages/core/src/models/Field.ts using createStateSetter—handles the actual reactive mutation for a single field instance.
Can I read specific properties without retrieving the entire field state?
Yes. Pass a selector function as the second argument to form.getFieldState(). For example: form.getFieldState('username', state => state.value) returns only the value property, while omitting the selector returns the complete IGeneralFieldState object.
Where is the field state type defined in Formily?
The field state interfaces are declared in packages/core/src/types.ts. IFieldState covers data-carrying fields, IVoidFieldState covers void fields (like layout containers), and IGeneralFieldState serves as the union type used throughout the state management APIs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →