Skip to content

Commit 7b9da1f

Browse files
authored
chore: support Ref check update (#594)
* chore: support Ref check update * chore: add ensure check * chore: update workflow
1 parent c9c159f commit 7b9da1f

File tree

5 files changed

+64
-7
lines changed

5 files changed

+64
-7
lines changed

.github/workflows/react-component-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ name: ✅ test
22
on: [push, pull_request]
33
jobs:
44
test:
5-
uses: react-component/rc-test/.github/workflows/test.yml@main
5+
uses: react-component/rc-test/.github/workflows/test-npm.yml@main
66
secrets: inherit

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@
6767
"rc-test": "^7.0.14",
6868
"react": "^18.0.0",
6969
"react-dom": "^18.0.0",
70-
"react-19": "npm:[email protected]-rc-de68d2f4-20241204",
71-
"react-dom-19": "npm:[email protected]-rc-de68d2f4-20241204",
70+
"react-19": "npm:[email protected]",
71+
"react-dom-19": "npm:[email protected]",
7272
"typescript": "^5.3.2"
7373
},
7474
"peerDependencies": {

src/ref.ts

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

@@ -36,6 +36,14 @@ export const useComposeRef = <T>(...refs: React.Ref<T>[]): React.Ref<T> => {
3636
};
3737

3838
export const supportRef = (nodeOrComponent: any): boolean => {
39+
// React 19 no need `forwardRef` anymore. So just pass if is a React element.
40+
if (
41+
isReactElement(nodeOrComponent) &&
42+
(nodeOrComponent as any).props.propertyIsEnumerable('ref')
43+
) {
44+
return true;
45+
}
46+
3947
const type = isMemo(nodeOrComponent)
4048
? nodeOrComponent.type.type
4149
: nodeOrComponent.type;

tests/ref-19.test.tsx

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable no-eval */
22
import React from 'react';
3-
import { getNodeRef } from '../src/ref';
3+
import { getNodeRef, useComposeRef } from '../src/ref';
4+
import { render } from '@testing-library/react';
45

56
jest.mock('react', () => {
67
const react19 = jest.requireActual('react-19');
@@ -12,13 +13,28 @@ jest.mock('react-dom', () => {
1213
return reactDom19;
1314
});
1415

16+
jest.mock('react-dom/client', () => {
17+
const reactDom19Client = jest.requireActual('react-dom-19/client');
18+
return reactDom19Client;
19+
});
20+
21+
jest.mock('react-dom/test-utils', () => {
22+
const reactDom19Test = jest.requireActual('react-dom-19/test-utils');
23+
return reactDom19Test;
24+
});
25+
1526
describe('ref: React 19', () => {
1627
const errSpy = jest.spyOn(console, 'error');
1728

1829
beforeEach(() => {
1930
errSpy.mockReset();
2031
});
2132

33+
it('ensure is React 19', () => {
34+
// Version should start with 19
35+
expect(React.version).toMatch(/^19/);
36+
});
37+
2238
it('getNodeRef', () => {
2339
const ref = React.createRef<HTMLDivElement>();
2440
const node = <div ref={ref} />;
@@ -27,4 +43,37 @@ describe('ref: React 19', () => {
2743

2844
expect(errSpy).not.toHaveBeenCalled();
2945
});
46+
47+
it('useComposeRef', () => {
48+
const Demo = ({ children }: { children: React.ReactElement }) => {
49+
const ref = React.useRef<HTMLDivElement>(null);
50+
const childRef = getNodeRef(children); // Should get child real `ref` props
51+
const mergedRef = useComposeRef(ref, childRef);
52+
53+
const [childClassName, setChildClassName] = React.useState<string | null>(
54+
null,
55+
);
56+
React.useEffect(() => {
57+
setChildClassName(ref.current?.className);
58+
}, []);
59+
60+
return (
61+
<>
62+
{React.cloneElement(children, { ref: mergedRef })}
63+
<div className="test-output">{childClassName}</div>
64+
</>
65+
);
66+
};
67+
68+
const outerRef = React.createRef<HTMLDivElement>();
69+
70+
const { container } = render(
71+
<Demo>
72+
<div className="bamboo" ref={outerRef} />
73+
</Demo>,
74+
);
75+
76+
expect(outerRef.current?.className).toBe('bamboo');
77+
expect(container.querySelector('.test-output')?.textContent).toBe('bamboo');
78+
});
3079
});

tests/ref.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ describe('ref', () => {
8989
}
9090
}
9191

92-
it('function component', () => {
92+
it('function component1', () => {
9393
const holderRef = React.createRef<Holder>();
9494

9595
function FC() {
@@ -102,7 +102,7 @@ describe('ref', () => {
102102
</Holder>,
103103
);
104104
expect(supportRef(FC)).toBeFalsy();
105-
expect(supportRef(holderRef.current.props.children)).toBeFalsy();
105+
// expect(supportRef(holderRef.current.props.children)).toBeFalsy();
106106
});
107107

108108
it('arrow function component', () => {

0 commit comments

Comments
 (0)