diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index b8eab99..25ae52a 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Merge incoming `style` prop on `ComboboxOptions`, `ListboxOptions`, `MenuItems`, and `PopoverPanel` components ([#3250](https://github.com/tailwindlabs/headlessui/pull/3250)) - Prevent focus on `` when it is `disabled` ([#3251](https://github.com/tailwindlabs/headlessui/pull/3251)) - Fix visual jitter in `Combobox` component when using native scrollbar ([#3190](https://github.com/tailwindlabs/headlessui/pull/3190)) +- Use `useId` instead of React internals (for React 19 compatibility) ([#3254](https://github.com/tailwindlabs/headlessui/pull/3254)) ## [2.0.4] - 2024-05-25 diff --git a/packages/@headlessui-react/src/utils/stable-collection.tsx b/packages/@headlessui-react/src/utils/stable-collection.tsx index e9feacf..e2b7c10 100644 --- a/packages/@headlessui-react/src/utils/stable-collection.tsx +++ b/packages/@headlessui-react/src/utils/stable-collection.tsx @@ -18,6 +18,9 @@ function createCollection() { } let renders = list.get(key) ?? 0 + // FIXME: This is a side-effect during render. `release` is only called in + // an effect cleanup so we may never release if we had to render multiple + // times before commit e.g. when a sibling suspends. list.set(key, renders + 1) let index = Array.from(list.keys()).indexOf(key) @@ -49,33 +52,8 @@ export function useStableCollectionIndex(group: string) { let collection = React.useContext(StableCollectionContext) if (!collection) throw new Error('You must wrap your component in a ') - let key = useStableCollectionKey() + let key = React.useId() let [idx, cleanupIdx] = collection.current.get(group, key) React.useEffect(() => cleanupIdx, []) return idx } - -/** - * Return a stable key based on the position of this node. - * - * @returns {symbol | string} - */ -function useStableCollectionKey() { - let owner = - // @ts-ignore - React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?.ReactCurrentOwner?.current ?? null - - // ssr: dev/prod - // client: prod - if (!owner) return Symbol() - - // client: dev - let indexes = [] - let fiber = owner - while (fiber) { - indexes.push(fiber.index) - fiber = fiber.return - } - - return '$.' + indexes.join('.') -}