Skip to content

Commit 73ebbd1

Browse files
authored
feat: getNodeRef (#545)
1 parent ed07cfc commit 73ebbd1

File tree

2 files changed

+40
-9
lines changed

2 files changed

+40
-9
lines changed

src/ref.ts

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type * as React from 'react';
2-
import { isValidElement } from 'react';
2+
import { isValidElement, version } from 'react';
33
import { ForwardRef, isFragment, isMemo } from 'react-is';
44
import useMemo from './hooks/useMemo';
55

@@ -64,14 +64,36 @@ interface RefAttributes<T> extends React.Attributes {
6464
ref: React.Ref<T>;
6565
}
6666

67+
function isReactElement(node: React.ReactNode) {
68+
return isValidElement(node) && !isFragment(node);
69+
}
70+
6771
export const supportNodeRef = <T = any>(
6872
node: React.ReactNode,
6973
): node is React.ReactElement & RefAttributes<T> => {
70-
if (!isValidElement(node)) {
71-
return false;
72-
}
73-
if (isFragment(node)) {
74-
return false;
75-
}
76-
return supportRef(node);
74+
return isReactElement(node) && supportRef(node);
7775
};
76+
77+
/**
78+
* In React 19. `ref` is not a property from node.
79+
* But a property from `props.ref`.
80+
* To check if `props.ref` exist or fallback to `ref`.
81+
*/
82+
export const getNodeRef: <T = any>(
83+
node: React.ReactNode,
84+
) => React.Ref<T> | null =
85+
Number(version.split('.')[0]) >= 19
86+
? // >= React 19
87+
node => {
88+
if (isReactElement(node)) {
89+
return (node as any).props.ref;
90+
}
91+
return null;
92+
}
93+
: // < React 19
94+
node => {
95+
if (isReactElement(node)) {
96+
return (node as any).ref;
97+
}
98+
return null;
99+
};

tests/ref.test.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
/* eslint-disable no-eval */
22
import { fireEvent, render } from '@testing-library/react';
3-
import React, { ReactNode } from 'react';
3+
import type { ReactNode } from 'react';
4+
import React from 'react';
45
import useEvent from '../src/hooks/useEvent';
56
import {
67
composeRef,
8+
getNodeRef,
79
supportNodeRef,
810
supportRef,
911
useComposeRef,
@@ -199,4 +201,11 @@ describe('ref', () => {
199201
expect(supportNodeRef(refCom) && refCom.ref).toBeTruthy();
200202
});
201203
});
204+
205+
it('getNodeRef', () => {
206+
const ref = React.createRef<HTMLDivElement>();
207+
const node = <div ref={ref} />;
208+
209+
expect(getNodeRef(node)).toBe(ref);
210+
});
202211
});

0 commit comments

Comments
 (0)