What Are Effects in Formily? Dynamic Form Behavior Explained

Effects in Formily are lifecycle functions that subscribe to field events—such as onFieldValueChange and onFieldInit—to reactively modify form state, trigger side effects, and control dynamic behavior without imperative UI code.

Formily, an open-source form solution by Alibaba, uses effects as its primary mechanism for handling complex, reactive form logic. These functions tap into the form's lifecycle to enable real-time field interactions, validation orchestration, and conditional visibility. Understanding how effects work is essential for building maintainable, data-driven forms in both React and Vue applications.

Understanding Effects in Formily

Effects are callback functions registered during form creation that receive the Form instance as their argument. Inside an effect, you use the form.subscribe method to listen for specific field lifecycle events.

The core event types include:

  • onFieldInit: Fires when a field component is created and mounted
  • onFieldValueChange: Triggers whenever a field's committed value changes
  • onFieldInputChange: Fires during input value changes (e.g., while typing)
  • onFieldValidate: Executes right before a field runs validation logic
  • onFieldReset: Occurs when a field resets to its initial value
  • onFieldBlur / onFieldFocus: Triggered when a field loses or gains focus

By registering listeners for these events, you can react to user interactions, modify dependent fields, call external APIs, or control the overall form workflow. The effect runs once during form instantiation and establishes persistent listeners for the form's lifetime.

How Effects Are Implemented in the Core

According to the alibaba/formily source code, the effects system is implemented across several key files in the formily_next branch.

In packages/core/src/models/Form.ts, the Form class stores an effects property. When you call createForm({ effects }), the constructor invokes runEffects(this, this.props.effects) to register your effect functions. The Form class also exposes addEffects and setEffects methods for dynamic registration.

The actual execution logic resides in packages/core/src/effects.ts. This file contains the runEffects runner that iterates over provided effect functions and executes them with the form instance context.

For framework integration, Formily provides convenience hooks:

Practical Examples of Formily Effects

Basic Effect in a Vue Component

In Vue 3, you combine createForm with useFormEffects to register lifecycle listeners. This example automatically calculates an isAdult checkbox when the age field changes:

<script setup>
import { createForm } from '@formily/core'
import { useFormEffects } from '@formily/vue'

const form = createForm({
  effects: (formInstance) => {
    formInstance.subscribe((field) => {
      if (field.path === 'age' && field.value !== undefined) {
        formInstance.setFieldState('isAdult', (state) => {
          state.value = field.value >= 18
        })
      }
    })
  },
})

useFormEffects(form)
</script>

Source: [use-form-effects.vue](https://github.com/alibaba/formily/blob/formily_next/packages/vue/docs/demos/api/hooks/use-form-effects.vue)

Effect in a React Component

The React implementation follows the same pattern using the FormProvider and useFormEffects hook from @formily/react. Here, a tax field updates automatically when price changes:

import { createForm } from '@formily/core'
import { FormProvider, useFormEffects } from '@formily/react'

const form = createForm({
  effects: (f) => {
    f.subscribe((field) => {
      if (field.path === 'price') {
        f.setFieldState('tax', (state) => {
          state.value = Number(field.value) * 0.2
        })
      }
    })
  },
})

export default function MyForm() {
  useFormEffects(form)
  return (
    <FormProvider form={form}>
      {/* form fields */}
    </FormProvider>
  )
}

Source: [useFormEffects.ts](https://github.com/alibaba/formily/blob/formily_next/packages/react/src/hooks/useFormEffects.ts)

Low-Level API with form.subscribe

For imperative control outside of React or Vue components, use the core form.subscribe method directly. This approach works in any JavaScript environment:

import { createForm } from '@formily/core'

const form = createForm()

form.subscribe((field) => {
  console.log(`Field ${field.path} changed to`, field.value)
})

Source: [Form.ts](https://github.com/alibaba/formily/blob/formily_next/packages/core/src/models/Form.ts)

Conditional Logic with the Query API

Effects can leverage form.query to perform bulk operations on matching fields. This example shows a field visibility toggle and pattern modification:

form.effects = (f) => {
  f.subscribe((field) => {
    if (field.path === 'country' && field.value === 'US') {
      f.setFieldState('state', (state) => {
        state.visible = true
      })
    }
  })

  // Bulk update using query API
  f.query('address.*').forEach((subField) => {
    subField.setPattern('readOnly')
  })
}

Source: [effects.ts](https://github.com/alibaba/formily/blob/formily_next/packages/core/src/effects.ts)

Summary

Frequently Asked Questions

What field lifecycle events can I listen to in Formily effects?

Formily effects support a comprehensive set of field events including onFieldInit (mounting), onFieldValueChange (value updates), onFieldInputChange (input typing), onFieldValidate (pre-validation), onFieldReset (reset actions), and onFieldBlur/onFieldFocus (focus management). These events allow you to hook into every stage of a field's existence to implement reactive logic.

How do I register effects in React and Vue components?

For React, import useFormEffects from @formily/react and call it with your form instance inside the component. For Vue, import useFormEffects from @formily/vue and call it within your setup function. Both hooks are implemented in packages/react/src/hooks/useFormEffects.ts and packages/vue/src/hooks/useFormEffects.ts respectively, and they automatically bind the effect lifecycle to the component.

Can I perform bulk field updates inside a Formily effect?

Yes. Use the form.query API to select multiple fields by path pattern (e.g., 'address.*'), then iterate over the results to apply state changes. This approach, implemented in the core effects system, lets you efficiently modify visibility, pattern, or values across field groups without individual subscriptions.

Where does Formily store and execute effect functions?

Effect functions are stored in the effects property of the Form class defined in packages/core/src/models/Form.ts. During form instantiation, the constructor calls runEffects from packages/core/src/effects.ts to execute each effect with the form instance, establishing the event subscription infrastructure.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →