API
observer returns a higher-order component that wraps whatever you pass in, so calling useObserver from inside a component still inserts an extra level in the tree. If you are building your own components, prefer calling useObserver directly so the reactive syncing stays local. The observer helper exists in @formily/vue primarily to keep Vue 2 compatibility, but for Vue 3-centric codebases the hook should be your first choice.
Internally, useObserver rewires Vue 3 reactivity with a non-public API. If you would rather avoid that hack, reach for formilyComputed, which exposes the Formily reaction as a standard Vue ComputedRef so most custom wrappers never need to touch useObserver.
observer
Description
Turns the component render function into a Formily Reaction. Every re-render collects dependencies, and only the exact reactive fields are tracked for updates.
Signature
interface IObserverOptions {
scheduler?: (updater: () => void) => void // optionally control when updates run
name?: string // name of the wrapped component
}
interface observer<T extends VueComponent> {
(component: T, options?: IObserverOptions): T
}Usage
<script>
import { observable } from '@formily/reactive'
import { observer } from '@silver-formily/reactive-vue'
export default observer({
data() {
// 能与 vue 的响应系统共存
const obs = observable({
value: 'Hello world',
})
return {
obs,
}
},
})
</script>
<template>
<div>
<div>
<input
:style="{
height: 28,
padding: '0 8px',
border: '2px solid #888',
borderRadius: 3,
}"
:value="obs.value"
@input="(e) => {
obs.value = e.target.value
}"
>
</div>
<div>{{ obs.value }}</div>
</div>
</template>useObserver Recommended
The hook that powers observer. Prefer calling it in setup/<script setup> to avoid extra wrapper components.
Signature
// Same options as observer
interface IObserverOptions {
scheduler?: (updater: () => void) => void
name?: string
}
interface useObserver {
(options?: IObserverOptions): void
}Usage
<script setup lang="ts">
import { observable } from '@formily/reactive'
import { useObserver } from '@silver-formily/reactive-vue'
useObserver()
const obs = observable({
value: 'Hello world',
})
function handleInput(event: Event) {
const target = event.target as HTMLInputElement | null
if (target) {
obs.value = target.value
}
}
</script>
<template>
<div>
<div>
<input
:style="{
height: 28,
padding: '0 8px',
border: '2px solid #888',
borderRadius: 3,
}"
:value="obs.value"
@input="handleInput"
>
</div>
<div>{{ obs.value }}</div>
</div>
</template>formilyComputed New
Converts a @formily/reactive computation into a Vue 3 ComputedRef. You can use it anywhere Vue expects a computed value (Pinia, props, etc.).
Signature
import type { IReactionOptions } from '@formily/reactive'
import type { ComputedRef } from 'vue'
// options default to { fireImmediately: true }
interface formilyComputed {
<T>(tracker: () => T, options?: IReactionOptions): ComputedRef<T>
}Usage
<script setup lang="ts">
import { observable } from '@formily/reactive'
import { formilyComputed } from '@silver-formily/reactive-vue'
const obs = observable({
value: 'Hello formilyComputed',
})
const uppercaseValue = formilyComputed(() => obs.value.toUpperCase())
const charCount = formilyComputed(() => obs.value.length)
function handleInput(event: Event) {
const target = event.target as HTMLInputElement | null
if (target) {
obs.value = target.value
}
}
</script>
<template>
<div>
<div>
<input
:style="{
height: 28,
padding: '0 8px',
border: '2px solid #888',
borderRadius: 3,
}"
:value="obs.value"
@input="handleInput"
>
</div>
<div>原始:{{ obs.value }}</div>
<div>formilyComputed(大写):{{ uppercaseValue }}</div>
<div>formilyComputed(长度):{{ charCount }}</div>
</div>
</template>