:useField Hook 讀取與操作字段狀態(tài)完全指南)
前端UI組件【免費(fèi)下載鏈接】formily Cross Device High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3項(xiàng)目地址https://gitcode.com/gh_mirrors/fo/formily點(diǎn)擊查看免費(fèi)下載導(dǎo)讀useField是 Formily Vue 體系中面向自定義組件開發(fā)的核心 Hook它讓任意位于 Field 組件子樹內(nèi)的自定義組件都能直接讀取當(dāng)前字段的屬性、值、校驗(yàn)狀態(tài)并主動調(diào)用字段模型的方法進(jìn)行狀態(tài)操作。本文基于 formily 倉庫中 packages/vue/docs/api/hooks/use-field.md 的官方文檔并結(jié)合formily/vue的實(shí)際源碼與測試用例深入講解useField的簽名、工作原理、類型檢查器配合方案與響應(yīng)式注意點(diǎn)讀完即可在自己的自定義組件中安全、高效地使用useField。一、useField 是什么用途與適用場景useField主要用在自定義組件內(nèi)用于完成兩類核心工作讀取當(dāng)前字段屬性例如讀取字段的value、display、pattern、path、address、校驗(yàn)反饋信息等操作字段狀態(tài)例如調(diào)用字段的setValue、setState、setDisplay、setPattern等方法主動驅(qū)動字段模型變化。它在所有 Field 組件的子樹內(nèi)都能使用——這里的 Field 組件是廣義的包括 Field、ObjectField、ArrayField、VoidField 等。以 RecursionField 為例它在setup中通過const parentRef useField()獲取父級字段用于計(jì)算子字段的basePath這正是Field 子樹內(nèi)可用的典型體現(xiàn)。注意useField拿到的是GeneralField通用字段模型它涵蓋了 Field、ArrayField、ObjectField、VoidField 四類字段的公共能力。如果需要針對不同類型的字段做差異化處理請配合 Type Checker類型檢查器使用下文第五節(jié)詳解。二、簽名與類型定義官方文檔給出的簽名為interface useField { (): RefField }對照倉庫中 packages/vue/src/hooks/useField.ts 的真實(shí)實(shí)現(xiàn)簽名更為精確import { inject, Ref, ref } from vue-demi import { GeneralField } from formily/core import { FieldSymbol } from ../shared/context export const useField T GeneralField(): RefT { return inject(FieldSymbol, ref()) as any }關(guān)鍵點(diǎn)說明泛型參數(shù)T默認(rèn)返回RefGeneralField。你可以顯式傳入更具體的字段類型例如useFieldFieldType()這在 packages/vue/src/tests/field.spec.ts 的useFormEffects測試用例中就有實(shí)際應(yīng)用返回值是RefT即一個(gè) Vue 響應(yīng)式引用訪問時(shí)需要通過.value解包例如fieldRef.value.setValue(123)返回inject(FieldSymbol, ref())從依賴注入容器中取出當(dāng)前字段引用若取不到則回退為空的ref()保證在非字段上下文中調(diào)用也不會拋錯(cuò)。這里涉及的FieldSymbol定義于 packages/vue/src/shared/context.tsexport const FieldSymbol: InjectionKeyRefGeneralField Symbol(field)useField的全部導(dǎo)出由 packages/vue/src/hooks/index.ts 統(tǒng)一聚合與useForm、useFormEffects、useFieldSchema、useParentForm并列導(dǎo)出。三、工作原理provide / inject 注入鏈useField之所以能在所有 Field 子樹內(nèi)使用依賴 Vue 的依賴注入機(jī)制注入鏈如下提供方字段渲染組件 ReactiveField 在創(chuàng)建字段模型后調(diào)用provide(FieldSymbol, fieldRef)把當(dāng)前字段的Ref提供給整棵子樹消費(fèi)方任意子組件包括自定義組件、RecursionField、ReactiveField自身通過inject(FieldSymbol, ...)拿到最近的父級字段嵌套取值由于inject遵循就近原則在多級嵌套字段結(jié)構(gòu)中每個(gè)useField()拿到的一定是離自己最近的祖先字段。例如 ReactiveField.ts 中const parentRef useField()用于讀取父字段地址parentRef.value?.address再結(jié)合basePath創(chuàng)建子字段從而自動形成完整的字段地址鏈。從源碼結(jié)構(gòu)看Field/ObjectField/ArrayField/VoidField組件最終都會渲染為ReactiveField如 Field.ts 所示無論 Vue 2 還是 Vue 3 分支都指向ReactiveField因此這一注入機(jī)制對四類字段統(tǒng)一生效。四、基本用法在自定義組件中讀取與操作字段4.1 讀取字段屬性的最小示例參考 packages/vue/src/tests/field.spec.ts 中Input組件的寫法這是最經(jīng)典的useField用法import { defineComponent, h } from vue import { useField } from formily/vue const Input defineComponent({ props: [value], setup(props, { attrs, listeners }) { const fieldRef useField() return () { const field fieldRef.value return h(input, { class: test-input, attrs: { ...attrs, value: props.value, data-testid: field.path.toString(), // 讀取字段路徑 }, on: { ...listeners, input: listeners.change, }, }) } }, })在這個(gè)例子中field.path.toString()直接讀出了字段在表單中的路徑如cc.mm測試斷言getByTestId(cc.mm)也能證明嵌套字段路徑的正確性。除了path通過GeneralField你還能讀取field.value字段當(dāng)前值field.display/field.pattern字段的顯示模式與交互模式editable/disabled/readOnly/readPrettyfield.valid/field.errors/field.feedbacks字段校驗(yàn)狀態(tài)與反饋信息field.address/field.path字段在表單樹中的地址與路徑field.form所屬表單實(shí)例。其中display、pattern的取值與繼承邏輯定義于 packages/core/src/models/BaseField.ts它們會向上級聯(lián)父字段與表單的默認(rèn)值例如默認(rèn)display visible、pattern editable這解釋了為什么字段模型具有子隨父動的聯(lián)動表現(xiàn)。4.2 操作字段狀態(tài)useField拿到的字段模型本身是響應(yīng)式模型可直接調(diào)用其方法操作狀態(tài)例如const fieldRef useFieldFieldType() // 設(shè)置值 fieldRef.value.setValue(123) // 批量修改狀態(tài) fieldRef.value.setState((state) { state.value 123 state.pattern readPretty }) // 切換顯示/模式 fieldRef.value.setDisplay(hidden) fieldRef.value.setPattern(disabled)值得注意的是字段模型的setDisplay/setPattern同樣定義于 BaseField.ts其實(shí)現(xiàn)會在設(shè)置自身selfDisplay/selfPattern的同時(shí)維護(hù)與表單全局狀態(tài)的聯(lián)動關(guān)系。4.3 在自定義組件中使用泛型約束由于useField默認(rèn)返回GeneralField當(dāng)你確定組件只會掛載在普通Field下時(shí)可以傳入更精確的類型以獲得類型提示import { Field as FieldType } from formily/core import { useField } from formily/vue const fieldRef useFieldFieldType()這一寫法在 field.spec.ts 的useFormEffects測試中被實(shí)際使用并通過isVoidField(target)守衛(wèi)后調(diào)用fieldRef.value.setValue(...)。五、GeneralField 與 Type Checker按類型差異化處理useField返回的是GeneralField它只保證四類字段Field、ArrayField、ObjectField、VoidField的公共能力。若需按類型做差異化邏輯官方文檔明確建議配合Type Checker使用。Type Checker 位于 packages/core/src/shared/checkers.ts核心導(dǎo)出包括isFieldisArrayFieldisObjectFieldisVoidField典型寫法import { isVoidField, isField } from formily/core import { useField } from formily/vue const fieldRef useField() // 只對非 VoidField 做值操作 if (!isVoidField(fieldRef.value)) { fieldRef.value.onInput(new value) } // 只對普通 Field 做處理 if (isField(fieldRef.value)) { fieldRef.value.setValue(123) }在 RecursionField.ts 中schema 的typeobject/array/void及其他被分別路由到ObjectField、ArrayField、VoidField和Field這與 Type Checker 的分類體系一一對應(yīng)而在 ReactiveField.ts 渲染邏輯中也大量使用isVoidField(field)判斷是否注入value、disabled等屬性——例如 VoidField 不參與onInput值寫入普通 Field 則會根據(jù)pattern disabled || pattern readPretty自動設(shè)置disabled。這些實(shí)現(xiàn)細(xì)節(jié)印證了先做類型判斷再做字段操作的工程慣例。六、響應(yīng)式要點(diǎn)必須用 observer 包裹自定義組件官方文檔給出了明確警告如果要在自定義組件內(nèi)使用useField并響應(yīng)字段模型變化需要使用observer包裹自定義組件。原因在于useField返回的fieldRef是一個(gè)普通的Ref由shallowRef創(chuàng)建字段模型內(nèi)部的響應(yīng)式變化并不會自動觸發(fā)自定義組件的重渲染。只有通過 Formily 的響應(yīng)式觀察器observer來自formily/reactive-vue源碼位于 packages/reactive-vue/src/observer/包裹組件組件才會在字段模型的value、display、pattern等狀態(tài)變化時(shí)自動更新。正確的做法import { observer } from formily/reactive-vue import { defineComponent, h } from vue import { useField } from formily/vue const CustomField observer( defineComponent({ setup() { const fieldRef useField() return () { const field fieldRef.value // 字段 value 變化時(shí)此處會自動重新渲染 return h(div, {}, [String(field.value)]) } }, }) )反向印證在 ReactiveField.ts 中字段渲染組件本身就用observer({...})包裹因此字段模型的display、value變化能夠驅(qū)動表單 UI 實(shí)時(shí)刷新而自定義組件若不包裹observer則只能讀到初始時(shí)的字段狀態(tài)無法隨模型變化更新。測試方面field.spec.ts 的useFormEffects用例中CustomField組件在onFieldChange回調(diào)里調(diào)用fieldRef.value.setValue(target.value)隨后waitFor斷言custom-value節(jié)點(diǎn)的文本更新為123——這一過程正是字段狀態(tài)變化 → 組件響應(yīng)式更新的完整閉環(huán)驗(yàn)證。七、進(jìn)階useField 與其他 Hook 的組合7.1 與 useParentForm 組合useField是useParentForm的底層依賴。查看 packages/vue/src/hooks/useParentForm.ts 的實(shí)現(xiàn)export const useParentForm (): RefForm | ObjectField { const field useField() const form useForm() const findObjectParent (field: GeneralField) { if (!field) return form.value if (isObjectField(field)) return field return findObjectParent(field?.parent) } return computed(() findObjectParent(field.value)) }可見useParentForm通過useField()拿到當(dāng)前字段再沿field.parent向上查找最近的 ObjectField找不到則回退到 Form 實(shí)例——這是字段子樹內(nèi)可用與 Type Checker 相結(jié)合的一個(gè)經(jīng)典封裝案例也是自定義組件內(nèi)向上找容器/找表單的推薦手段。7.2 與 useFormEffects 組合在自定義組件中useField常與useFormEffects搭配實(shí)現(xiàn)字段聯(lián)動。參考 field.spec.ts 中的用例組件通過useFormEffects訂閱onFieldChange(aa, [value], ...)在回調(diào)里讀取目標(biāo)字段的新值并寫入當(dāng)前字段實(shí)現(xiàn)跨字段的值同步。這種方式將字段訂閱與字段操作解耦是動態(tài)表單聯(lián)動的最佳實(shí)踐之一。八、適用前提與使用限制必須位于字段子樹內(nèi)useField依賴provide注入只有在FormProvider→ 各類 Field 組件形成的嵌套結(jié)構(gòu)內(nèi)才能拿到字段脫離字段上下文時(shí)它返回空Refref()的默認(rèn)回退拿到的是 GeneralField需要具體類型能力如數(shù)組字段的move/remove、對象字段的setValues等時(shí)請配合 Type Checker 收窄類型響應(yīng)式更新依賴 observer不包裹observer時(shí)組件不會隨字段模型變化而重渲染Vue 2 / Vue 3 雙兼容formily/vue通過vue-demi實(shí)現(xiàn)跨版本支持useField在兩種環(huán)境中均可直接使用見 useField.ts 對vue-demi的引入以及 ReactiveField.ts 中針對 Vue 2 的createFieldInVue2兼容邏輯。結(jié)語useField雖只有短短幾行實(shí)現(xiàn)卻是打通自定義組件 ? 字段模型的關(guān)鍵橋梁。理解其inject/provide注入機(jī)制、Ref返回值約定、Type Checker 類型分派與observer響應(yīng)式約束就能在 Formily Vue 生態(tài)中自由構(gòu)建高性能的自定義字段組件。建議進(jìn)一步閱讀 useFieldSchema、useForm、useParentForm 等相鄰 Hook 文檔以及 packages/vue/src/tests/field.spec.ts 中的完整測試用例以獲得更系統(tǒng)的掌握。贊分享前端UI組件【免費(fèi)下載鏈接】formily Cross Device High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3項(xiàng)目地址https://gitcode.com/gh_mirrors/fo/formily點(diǎn)擊查看免費(fèi)下載相關(guān)推薦Formily React useField Hook 完全指南在自定義組件中讀取字段模型與狀態(tài)Formily React useField Hook 完全指南在自定義組件中讀取字段模型與狀態(tài) 導(dǎo)讀 useField 是 Formily React 體系前端UI組件Formily React 中 useFieldSchema Hook 完全指南在自定義組件中讀取當(dāng)前字段 SchemaFormily React 中 useFieldSchema Hook 完全指南在自定義組件中讀取當(dāng)前字段 Schema 導(dǎo)讀 useFieldSchema前端UI組件Formily Vue useFieldSchema 完全指南在自定義組件中讀取當(dāng)前字段的 Schema 信息Formily Vue useFieldSchema 完全指南在自定義組件中讀取當(dāng)前字段的 Schema 信息 導(dǎo)讀 useFieldSchema 是 For前端UI組件創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考