Skip to content

Commit 6a5e1c1

Browse files
fix(react-form): fix server hydration issues (#1913)
* fix(react-form): fix cache components support Attempts to resolve #1907 Removes `Math.random()` introduced in #1893 from the hot path allowing the page to be pre-built with a a user provided form id. source: https://nextjs.org/docs/app/getting-started/cache-components#non-deterministic-operations * generate changeset * Change to patch * feat: use useId on React 18+ with a fallback to uuid on React 17 * chore: incredible review feedback * update changelog * chore: rename file * import correctly * return a stable UUID reference * chore: switch from useMemo to useState * ci: apply automated fixes and generate docs --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 883867d commit 6a5e1c1

File tree

4 files changed

+22
-2
lines changed

4 files changed

+22
-2
lines changed

.changeset/metal-times-remain.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@tanstack/react-form': patch
3+
'@tanstack/react-form-nextjs': patch
4+
---
5+
6+
use React 18's useId hook by default for formId generation, only calling Math.random() as a fallback if no formId is provided.

packages/react-form/src/useForm.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
'use client'
22

3-
import { FormApi, functionalUpdate, uuid } from '@tanstack/form-core'
3+
import { FormApi, functionalUpdate } from '@tanstack/form-core'
44
import { useStore } from '@tanstack/react-store'
55
import { useMemo, useState } from 'react'
66
import { Field } from './useField'
77
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
8+
import { useFormId } from './useFormId'
89
import type {
910
AnyFormApi,
1011
AnyFormState,
@@ -184,7 +185,7 @@ export function useForm<
184185
TSubmitMeta
185186
>,
186187
) {
187-
const fallbackFormId = useState(() => uuid())[0]
188+
const fallbackFormId = useFormId()
188189
const [prevFormId, setPrevFormId] = useState<string>(opts?.formId as never)
189190

190191
const [formApi, setFormApi] = useState(() => {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import * as React from 'react'
2+
import { useUUID } from './useUUID'
3+
4+
/** React 17 does not have the useId hook, so we use a random uuid as a fallback. */
5+
export const useFormId =
6+
React.version.split('.')[0] === '17' ? useUUID : React.useId

packages/react-form/src/useUUID.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { useState } from 'react'
2+
import { uuid } from '@tanstack/form-core'
3+
4+
/** Generates a random UUID. and returns a stable reference to it. */
5+
export function useUUID() {
6+
return useState<string>(() => uuid())[0]
7+
}

0 commit comments

Comments
 (0)