Capítulo 10 de 29
There's no built-in "async defaultValues" option — the documented pattern is to fetch with TanStack Query (or any async source) first, gate rendering on isLoading, and only construct the useForm call once real data is available.
defaultValues is read once at form-instance creation — it isn't reactive to a later-arriving async value on its own, so the fetch must resolve before useForm runs with real data.useQuery (ch025 of tanstack-query-docs, if present) supplying data, with defaultValues: { field: data?.field ?? '' } as a fallback while loading.if (isLoading) return <p>Loading...</p>) prevents rendering the form with empty/wrong defaults before the fetch resolves.Fetch first, form second: call useQuery to load the record, branch on isLoading to show a placeholder, and only reach the useForm call (with defaultValues sourced from data) once loading is false. Because useQuery caches by queryKey, repeat mounts of the same form don't re-fetch unnecessarily — the async-initial-values problem and TanStack Query's caching solve each other simultaneously rather than needing separate plumbing.
const { data, isLoading } = useQuery({
queryKey: ['data'],
queryFn: async () => fetchProfile(),
})
const form = useForm({
defaultValues: { firstName: data?.firstName ?? '', lastName: data?.lastName ?? '' },
onSubmit: async ({ value }) => console.log(value),
})
if (isLoading) return <p>Loading...</p>
// render form
defaultValues reactively after the form is created — gate the useForm call itself behind the loading state instead.?? '' in the example) rather than leaving fields undefined, which can trigger the "uncontrolled to controlled" warning (ch023 Debugging).tanstack-query-docs (sibling skill, if present): the caching layer this pattern typically relies on.