useFormEffects
Description
Mainly used inside custom components to inject effect logic into the current Form instance, for implementing more complex scenario-specific components. The effects are automatically cleaned up when the component unmounts, synchronous StrictMode effect replay retains the existing subscription.
Keep the same form instance for the lifetime of a mounted FormProvider. To replace the entire form, remount FormProvider and its subtree, for example with <FormProvider key={form.id} form={form}>. Do not only replace the existing provider's form prop while reusing its subtree: useFormEffects registers on mount and does not rebind when that prop changes. Unmounting the old subtree cleans up its subscriptions; mounting the new subtree registers new ones.
Signature
import type { Form } from '@silver-formily/core'
declare function useFormEffects(effects?: (form: Form) => void): voidUsage
import { createForm, isField, onFieldReact } from '@silver-formily/core'
import { Field, FormConsumer, FormProvider, useFormEffects } from '@silver-formily/react'
import { Button, Form, Input } from 'antd'
import { useState } from 'react'
function Custom() {
// 通过 useFormEffects 往当前 Form 注入副作用逻辑,组件卸载时自动清理
useFormEffects(() => {
onFieldReact('custom.bb', (field) => {
if (!isField(field))
return
field.value = field.query('.aa').get('value')
})
})
return (
<>
<Field
name="aa"
decorator={[Form.Item]}
component={[Input, { placeholder: 'aa' }]}
/>
<Field
name="bb"
decorator={[Form.Item]}
component={[Input, { placeholder: 'bb' }]}
/>
</>
)
}
function createDemoForm() {
return createForm({
effects() {
onFieldReact('custom.aa', (field) => {
if (!isField(field))
return
field.value = field.query('input').get('value')
})
},
})
}
export default function Demo() {
const [form, setForm] = useState(createDemoForm)
return (
<FormProvider key={form.id} form={form}>
<Button onClick={() => setForm(createDemoForm())}>重新挂载新表单</Button>
<Field
name="input"
decorator={[Form.Item]}
component={[Input, { placeholder: 'input' }]}
/>
<Field name="custom" component={[Custom]} />
<FormConsumer>
{_form => JSON.stringify(_form.values)}
</FormConsumer>
</FormProvider>
)
}import { createForm, isField, onFieldReact } from '@silver-formily/core'
import { Field, FormConsumer, FormProvider, useFormEffects } from '@silver-formily/react'
import { Button, Form, Input } from 'antd'
import { useState } from 'react'
function Custom() {
// 通过 useFormEffects 往当前 Form 注入副作用逻辑,组件卸载时自动清理
useFormEffects(() => {
onFieldReact('custom.bb', (field) => {
if (!isField(field))
return
field.value = field.query('.aa').get('value')
})
})
return (
<>
<Field
name="aa"
decorator={[Form.Item]}
component={[Input, { placeholder: 'aa' }]}
/>
<Field
name="bb"
decorator={[Form.Item]}
component={[Input, { placeholder: 'bb' }]}
/>
</>
)
}
function createDemoForm() {
return createForm({
effects() {
onFieldReact('custom.aa', (field) => {
if (!isField(field))
return
field.value = field.query('input').get('value')
})
},
})
}
export default function Demo() {
const [form, setForm] = useState(createDemoForm)
return (
<FormProvider key={form.id} form={form}>
<Button onClick={() => setForm(createDemoForm())}>重新挂载新表单</Button>
<Field
name="input"
decorator={[Form.Item]}
component={[Input, { placeholder: 'input' }]}
/>
<Field name="custom" component={[Custom]} />
<FormConsumer>
{_form => JSON.stringify(_form.values)}
</FormConsumer>
</FormProvider>
)
}
Registration runs during the initial render, before child fields are created, so it can observe onFieldInit. Re-rendering does not rerun registration or replace captured callbacks. Keep captured inputs stable, or remount the subscribing component when new inputs require a new subscription. Final cleanup is deferred to a microtask; resources from abandoned renders are handled by the existing garbage collector.