From 7b9da1f42d1d2661b5cfe83205391b1fa5c44fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Fri, 6 Dec 2024 17:54:07 +0800 Subject: [PATCH] chore: support Ref check update (#594) * chore: support Ref check update * chore: add ensure check * chore: update workflow --- .github/workflows/react-component-ci.yml | 2 +- package.json | 4 +- src/ref.ts | 10 ++++- tests/ref-19.test.tsx | 51 +++++++++++++++++++++++- tests/ref.test.tsx | 4 +- 5 files changed, 64 insertions(+), 7 deletions(-) diff --git a/.github/workflows/react-component-ci.yml b/.github/workflows/react-component-ci.yml index f860ff10..21c24587 100644 --- a/.github/workflows/react-component-ci.yml +++ b/.github/workflows/react-component-ci.yml @@ -2,5 +2,5 @@ name: ✅ test on: [push, pull_request] jobs: test: - uses: react-component/rc-test/.github/workflows/test.yml@main + uses: react-component/rc-test/.github/workflows/test-npm.yml@main secrets: inherit diff --git a/package.json b/package.json index be637bb0..62fbfb22 100644 --- a/package.json +++ b/package.json @@ -67,8 +67,8 @@ "rc-test": "^7.0.14", "react": "^18.0.0", "react-dom": "^18.0.0", - "react-19": "npm:react@19.0.0-rc-de68d2f4-20241204", - "react-dom-19": "npm:react-dom@19.0.0-rc-de68d2f4-20241204", + "react-19": "npm:react@19.0.0", + "react-dom-19": "npm:react-dom@19.0.0", "typescript": "^5.3.2" }, "peerDependencies": { diff --git a/src/ref.ts b/src/ref.ts index 66e39d88..0cfb6ef0 100644 --- a/src/ref.ts +++ b/src/ref.ts @@ -1,5 +1,5 @@ import type * as React from 'react'; -import { isValidElement, version } from 'react'; +import { isValidElement } from 'react'; import { ForwardRef, isFragment, isMemo } from 'react-is'; import useMemo from './hooks/useMemo'; @@ -36,6 +36,14 @@ export const useComposeRef = (...refs: React.Ref[]): React.Ref => { }; export const supportRef = (nodeOrComponent: any): boolean => { + // React 19 no need `forwardRef` anymore. So just pass if is a React element. + if ( + isReactElement(nodeOrComponent) && + (nodeOrComponent as any).props.propertyIsEnumerable('ref') + ) { + return true; + } + const type = isMemo(nodeOrComponent) ? nodeOrComponent.type.type : nodeOrComponent.type; diff --git a/tests/ref-19.test.tsx b/tests/ref-19.test.tsx index 2d3d3341..fab08af2 100644 --- a/tests/ref-19.test.tsx +++ b/tests/ref-19.test.tsx @@ -1,6 +1,7 @@ /* eslint-disable no-eval */ import React from 'react'; -import { getNodeRef } from '../src/ref'; +import { getNodeRef, useComposeRef } from '../src/ref'; +import { render } from '@testing-library/react'; jest.mock('react', () => { const react19 = jest.requireActual('react-19'); @@ -12,6 +13,16 @@ jest.mock('react-dom', () => { return reactDom19; }); +jest.mock('react-dom/client', () => { + const reactDom19Client = jest.requireActual('react-dom-19/client'); + return reactDom19Client; +}); + +jest.mock('react-dom/test-utils', () => { + const reactDom19Test = jest.requireActual('react-dom-19/test-utils'); + return reactDom19Test; +}); + describe('ref: React 19', () => { const errSpy = jest.spyOn(console, 'error'); @@ -19,6 +30,11 @@ describe('ref: React 19', () => { errSpy.mockReset(); }); + it('ensure is React 19', () => { + // Version should start with 19 + expect(React.version).toMatch(/^19/); + }); + it('getNodeRef', () => { const ref = React.createRef(); const node =
; @@ -27,4 +43,37 @@ describe('ref: React 19', () => { expect(errSpy).not.toHaveBeenCalled(); }); + + it('useComposeRef', () => { + const Demo = ({ children }: { children: React.ReactElement }) => { + const ref = React.useRef(null); + const childRef = getNodeRef(children); // Should get child real `ref` props + const mergedRef = useComposeRef(ref, childRef); + + const [childClassName, setChildClassName] = React.useState( + null, + ); + React.useEffect(() => { + setChildClassName(ref.current?.className); + }, []); + + return ( + <> + {React.cloneElement(children, { ref: mergedRef })} +
{childClassName}
+ + ); + }; + + const outerRef = React.createRef(); + + const { container } = render( + +
+ , + ); + + expect(outerRef.current?.className).toBe('bamboo'); + expect(container.querySelector('.test-output')?.textContent).toBe('bamboo'); + }); }); diff --git a/tests/ref.test.tsx b/tests/ref.test.tsx index 6ca63d0c..1f892234 100644 --- a/tests/ref.test.tsx +++ b/tests/ref.test.tsx @@ -89,7 +89,7 @@ describe('ref', () => { } } - it('function component', () => { + it('function component1', () => { const holderRef = React.createRef(); function FC() { @@ -102,7 +102,7 @@ describe('ref', () => { , ); expect(supportRef(FC)).toBeFalsy(); - expect(supportRef(holderRef.current.props.children)).toBeFalsy(); + // expect(supportRef(holderRef.current.props.children)).toBeFalsy(); }); it('arrow function component', () => {