From e700d72550a495f7b85a67350bd5f1df3eea960a Mon Sep 17 00:00:00 2001 From: GuinsooRocky Date: Fri, 8 May 2026 20:38:51 +0900 Subject: [PATCH 1/2] fix: getNodeRef should not fallback to element.ref in React 19 Regression of #593: propertyIsEnumerable('ref') returns false when the element has no ref prop, causing fallback to element.ref which triggers React 19's deprecation warning. Restore the version-based branch introduced in #545. --- src/ref.ts | 12 +++++++----- tests/ref-19.test.tsx | 10 ++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/ref.ts b/src/ref.ts index fd9513b9..dd289383 100644 --- a/src/ref.ts +++ b/src/ref.ts @@ -90,17 +90,19 @@ export const supportNodeRef = ( /** * In React 19. `ref` is not a property from node. * But a property from `props.ref`. - * To check if `props.ref` exist or fallback to `ref`. + * In < React 19, `ref` lives on the element itself (`element.ref`). */ export const getNodeRef: ( node: React.ReactNode, ) => React.Ref | null = node => { if (node && isReactElement(node)) { const ele = node as any; - - // Source from: - // https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/getReactNodeRef/getReactNodeRef.ts - return ele.props.propertyIsEnumerable('ref') ? ele.props.ref : ele.ref; + // React 19: `ref` is a regular prop and reading `element.ref` triggers a + // deprecation warning, even when the prop is absent. Branch on the React + // major version to avoid touching `element.ref` on React 19+. + return ReactMajorVersion >= 19 + ? (ele.props.ref ?? null) + : ele.ref; } return null; }; diff --git a/tests/ref-19.test.tsx b/tests/ref-19.test.tsx index b51d2ce4..906577f6 100644 --- a/tests/ref-19.test.tsx +++ b/tests/ref-19.test.tsx @@ -44,6 +44,16 @@ describe('ref: React 19', () => { expect(errSpy).not.toHaveBeenCalled(); }); + it('getNodeRef on element without ref does not access element.ref', () => { + // Regression: previous propertyIsEnumerable('ref') check fell back to + // `element.ref` for elements rendered without an explicit ref prop, which + // triggers React 19's "Accessing element.ref was removed" warning. + const node =
; + + expect(getNodeRef(node)).toBeNull(); + expect(errSpy).not.toHaveBeenCalled(); + }); + it('useComposeRef', () => { const Demo: React.FC = ({ children }) => { const ref = React.useRef(null); From fabcc48bc7616f0a37a688127b371b6eab3feb6a Mon Sep 17 00:00:00 2001 From: GuinsooRocky Date: Fri, 8 May 2026 23:06:08 +0900 Subject: [PATCH 2/2] fix: align getNodeRef legacy branch return type with `?? null` Address @gemini-code-assist review on #759: ensure both branches return `React.Ref | null` for consumers of this utility, even on the legacy React (<19) path where `element.ref` could theoretically be undefined. --- src/ref.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ref.ts b/src/ref.ts index dd289383..06fd5741 100644 --- a/src/ref.ts +++ b/src/ref.ts @@ -102,7 +102,7 @@ export const getNodeRef: ( // major version to avoid touching `element.ref` on React 19+. return ReactMajorVersion >= 19 ? (ele.props.ref ?? null) - : ele.ref; + : (ele.ref ?? null); } return null; };