[v2][vue] Field components registered with `createFormHook` don't rerender on field state changes, and lose their field API after `form.reset()`
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 新手友好度
- 35/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- typescript
- 领域
- frontend
调研方向
从 src/AppForm/fieldComponentHelpers.lib.ts 和 src/VueForm/Components.lib.ts 开始,然后检查 PR #2392 中引用的回归测试。使用 Vue 表单测试设置重现该故障,并验证注入的字段组件会在验证发生变化后更新,并且在 form.reset() 后仍会更新表单。
由索引模型根据 Issue 内容生成。
描述
Describe the bug
In @tanstack/[email protected], field components registered through createFormHook with getFormHookHelpers().fieldComponent.strict() (the pattern used in examples/vue/large-form) only render once:
- They don't rerender when the field state changes. After a change that produces a validation error, the form state is correct (
form.getFieldMeta('name').errorscontains the error andmeta.isInvalidistrue), but the injected component keeps showing its first render: no error message andaria-invalid="false". Rendering the same field directly inside the<form.Field>slot updates as expected. - They lose their field API after
form.reset(). After a reset, typing into the injected component no longer updates the form value.
Root cause
wrapField(src/AppForm/fieldComponentHelpers.lib.ts) injects the field API and passes the same object as a prop on every render. The parentFieldrerenders its slot because of its own subscription, but Vue skips updating the injected component because its props are unchanged (same object reference), and the child's reads of the field API getters are not tracked by Vue.createFieldComponent(src/VueForm/Components.lib.ts) callsprovide(fieldContext, fieldApi.value)once during setup.useFieldreplacesfieldApi.valuewhenresetVersionchanges, so afterform.reset()the injected component keeps the old instance. The comment above that line ("Field APIs are stable for a mounted name… the parent subscription handles state-driven renders") doesn't hold for injected components.
Your minimal, reproducible example
Regression tests are included in PR #2392. Minimal Vue SFC repro:
<!-- TextField.vue — same as examples/vue/large-form/src/components/TextField.vue -->
<script setup lang="ts">
import type { FieldWithValue } from '@tanstack/vue-form'
defineProps<{ field: FieldWithValue<string>; label: string }>()
</script>
<template>
<label :for="field.name">{{ label }}</label>
<input
:id="field.name"
:value="field.value"
:aria-invalid="field.meta.isInvalid"
@input="field.handleChange(($event.target as HTMLInputElement).value)"
/>
<p v-for="error in field.errors" :key="error.message">{{ error.message }}</p>
</template>
<!-- Form.vue -->
<script setup lang="ts">
import { createFormHook, getFormHookHelpers } from '@tanstack/vue-form'
import TextField from './TextField.vue'
const { fieldComponent } = getFormHookHelpers()
const { useAppForm } = createFormHook({
fieldComponents: { TextField: fieldComponent.strict(TextField, 'field') },
formComponents: {},
})
const form = useAppForm({
defaultValues: { name: '' },
validators: [
{
triggers: ['change'],
run: ({ value, createErrorMap }) => {
const errors = createErrorMap()
if (value.name.length < 2) errors.fields.name = 'At least 2 characters'
return errors
},
},
],
})
</script>
<template>
<form.Field name="name" v-slot="{ field }">
<field.TextField label="Name" />
</form.Field>
<button type="button" @click="form.reset()">Reset</button>
</template>
Steps to reproduce
- Render
Form.vue. - Type one character into the input.
form.getFieldMeta('name').errorscontains "At least 2 characters", butTextFieldshows no error andaria-invalidstays"false".- Click Reset, then type again:
form.state.values.namedoesn't change.
Expected behavior
Injected field components rerender when their field state changes and keep working after form.reset(), the same as markup rendered directly inside the <form.Field> slot.
How often does this bug happen?
Every time
Platform
- macOS, Node 24
- Reproduced in Vitest with both happy-dom and jsdom (the upstream
packages/vue-formtest setup) - Vue 3.6.0-rc.8
TanStack Form adapter
vue-form
TanStack Form version
2.0.0-alpha.2 (also reproduced on the alpha branch at 6e5b809)
TypeScript version
6.0.3
Additional context
I opened PR #2392 with a fix and two regression tests. Both tests fail before the change and pass after it.
- 主要语言
- TypeScript
- 星标
- 6.8k
- 派生
- 705
- 平均合并
- 1 天 7 小时
- 30 天内合并 PR
- 13
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
TanStack/form 的其他 Issue
-
[v2] FieldWithValue<T> erases field.name to any instead of string可能已有人在做 @Priyeshshrivastav 于 1 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 79/100
维护者通常 1 天内回复
-
`isDefaultValue` is wrong when a field-level `defaultValue` is `null`可能已有人在做 @fenet-as 于 24 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复
-
Async validator doesn't re-trigger `isValidating` after first failed validation可能已有人在做 @drewsephski 于 28 天前认领。 未关闭
难度 2/5 1-2 天 新手友好度 72/100
维护者通常 1 天内回复
-
[v2 alpha] devtools are always light mode可能已有人在做 @dikshit-n 于 62 天前认领。 未关闭area: runtime scope: devtools type: bug v2
难度 2/5 1-3 小时 新手友好度 65/100
维护者通常 1 天内回复
-
FormGroupApi.getRelatedFields and FieldApi.validate() use unguarded startsWith for group membership, matching unrelated fields with a shared name prefix可能已有人在做 @HDPark95 于 81 天前认领。 未关闭area: runtime scope: core type: bug v1
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
相似的 Issue
-
unwrapDatabaseError masks real DB errors with TypeError: Cannot convert object to primitive value未关闭
难度 2/5 1-3 小时 新手友好度 74/100
NEARBuilders/everything-dev#798 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
vercel-labs/durable-harness#53 ·
维护者通常 1 天内回复
-
[Bug]: Redesign tab bars ignore clicks on Linux: hidden chat layers keep window drag regions可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
experiência: a doc manda subir para o Micro do Supabase, mas não diz que exige plano pago nem quanto custa可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭area/docs area/ui enhancement
难度 1/5 1-3 小时 新手友好度 88/100
melgarafael/DeskcommCRM#4098 ·
维护者通常 1 天内回复
-
dependencies platform: ios
难度 1/5 1-3 小时 新手友好度 78/100
software-mansion/react-native-executorch#1617 ·
维护者通常 1 天内回复