Skip to content

Commit 522b4fe

Browse files
RoxannejzombieJ
andauthored
feat: Remove findDOMNode from rc-css-motion (#59)
* feat: Remove findDOMNode from rc-css-motion * feat: Remove findDOMNode from rc-css-motion * chore: clean up wrapper * test: fix test case * chore: fix lint --------- Co-authored-by: 二货机器人 <smith3816@gmail.com>
1 parent 96996a1 commit 522b4fe

File tree

10 files changed

+49
-62
lines changed

10 files changed

+49
-62
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"docs:build": "dumi build",
3232
"docs:deploy": "gh-pages -d .doc",
3333
"lint": "eslint src/ --ext .tsx,.ts",
34+
"lint:tsc": "tsc --noEmit",
3435
"now-build": "npm run docs:build",
3536
"prepare": "husky install",
3637
"prepublishOnly": "npm run compile && np --yolo --no-publish",
@@ -47,8 +48,8 @@
4748
},
4849
"dependencies": {
4950
"@babel/runtime": "^7.11.1",
50-
"classnames": "^2.2.1",
51-
"rc-util": "^5.44.0"
51+
"@rc-component/util": "^1.2.0",
52+
"classnames": "^2.2.1"
5253
},
5354
"devDependencies": {
5455
"@rc-component/father-plugin": "^1.0.1",

src/CSSMotion.tsx

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
/* eslint-disable react/default-props-match-prop-types, react/no-multi-comp, react/prop-types */
2+
import { getDOM } from '@rc-component/util/lib/Dom/findDOMNode';
3+
import { getNodeRef, supportRef } from '@rc-component/util/lib/ref';
24
import classNames from 'classnames';
3-
import findDOMNode from 'rc-util/lib/Dom/findDOMNode';
4-
import { fillRef, getNodeRef, supportRef } from 'rc-util/lib/ref';
55
import * as React from 'react';
66
import { useRef } from 'react';
77
import { Context } from './context';
8-
import DomWrapper from './DomWrapper';
98
import useStatus from './hooks/useStatus';
109
import { isActive } from './hooks/useStepQueue';
1110
import type {
@@ -91,7 +90,7 @@ export interface CSSMotionProps {
9190
style?: React.CSSProperties;
9291
[key: string]: any;
9392
},
94-
ref: (node: any) => void,
93+
ref: React.Ref<any>,
9594
) => React.ReactElement;
9695
}
9796

@@ -137,22 +136,9 @@ export function genCSSMotion(config: CSSMotionConfig) {
137136

138137
// Ref to the react node, it may be a HTMLElement
139138
const nodeRef = useRef<any>();
140-
// Ref to the dom wrapper in case ref can not pass to HTMLElement
141-
const wrapperNodeRef = useRef();
142139

143140
function getDomElement() {
144-
try {
145-
// Here we're avoiding call for findDOMNode since it's deprecated
146-
// in strict mode. We're calling it only when node ref is not
147-
// an instance of DOM HTMLElement. Otherwise use
148-
// findDOMNode as a final resort
149-
return nodeRef.current instanceof HTMLElement
150-
? nodeRef.current
151-
: findDOMNode<HTMLElement>(wrapperNodeRef.current);
152-
} catch (e) {
153-
// Only happen when `motionDeadline` trigger but element removed.
154-
return null;
155-
}
141+
return getDOM(nodeRef.current) as HTMLElement;
156142
}
157143

158144
const [status, statusStep, statusStyle, mergedVisible] = useStatus(
@@ -170,13 +156,7 @@ export function genCSSMotion(config: CSSMotionConfig) {
170156
}
171157

172158
// ====================== Refs ======================
173-
const setNodeRef = React.useCallback(
174-
(node: any) => {
175-
nodeRef.current = node;
176-
fillRef(ref, node);
177-
},
178-
[ref],
179-
);
159+
React.useImperativeHandle(ref, () => getDomElement());
180160

181161
// ===================== Render =====================
182162
let motionChildren: React.ReactNode;
@@ -188,16 +168,16 @@ export function genCSSMotion(config: CSSMotionConfig) {
188168
} else if (status === STATUS_NONE) {
189169
// Stable children
190170
if (mergedVisible) {
191-
motionChildren = children({ ...mergedProps }, setNodeRef);
171+
motionChildren = children({ ...mergedProps }, nodeRef);
192172
} else if (!removeOnLeave && renderedRef.current && leavedClassName) {
193173
motionChildren = children(
194174
{ ...mergedProps, className: leavedClassName },
195-
setNodeRef,
175+
nodeRef,
196176
);
197177
} else if (forceRender || (!removeOnLeave && !leavedClassName)) {
198178
motionChildren = children(
199179
{ ...mergedProps, style: { display: 'none' } },
200-
setNodeRef,
180+
nodeRef,
201181
);
202182
} else {
203183
motionChildren = null;
@@ -227,7 +207,7 @@ export function genCSSMotion(config: CSSMotionConfig) {
227207
}),
228208
style: statusStyle,
229209
},
230-
setNodeRef,
210+
nodeRef,
231211
);
232212
}
233213

@@ -239,13 +219,13 @@ export function genCSSMotion(config: CSSMotionConfig) {
239219
motionChildren = React.cloneElement(
240220
motionChildren as React.ReactElement,
241221
{
242-
ref: setNodeRef,
222+
ref: nodeRef,
243223
},
244224
);
245225
}
246226
}
247227

248-
return <DomWrapper ref={wrapperNodeRef}>{motionChildren}</DomWrapper>;
228+
return motionChildren as React.ReactElement;
249229
});
250230

251231
CSSMotion.displayName = 'CSSMotion';

src/CSSMotionList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export interface CSSMotionListProps
5555
index?: number;
5656
[key: string]: any;
5757
},
58-
ref: (node: any) => void,
58+
ref: React.Ref<any>,
5959
) => React.ReactElement;
6060
}
6161

src/DomWrapper.tsx

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/hooks/useIsomorphicLayoutEffect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import canUseDom from 'rc-util/lib/Dom/canUseDom';
1+
import canUseDom from '@rc-component/util/lib/Dom/canUseDom';
22
import { useEffect, useLayoutEffect } from 'react';
33

44
// It's safe to use `useLayoutEffect` but the warning is annoying

src/hooks/useNextFrame.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import raf from 'rc-util/lib/raf';
1+
import raf from '@rc-component/util/lib/raf';
22
import * as React from 'react';
33

44
export default (): [

src/hooks/useStatus.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { useEvent } from 'rc-util';
2-
import useState from 'rc-util/lib/hooks/useState';
3-
import useSyncState from 'rc-util/lib/hooks/useSyncState';
1+
import { useEvent } from '@rc-component/util';
2+
import useState from '@rc-component/util/lib/hooks/useState';
3+
import useSyncState from '@rc-component/util/lib/hooks/useSyncState';
44
import * as React from 'react';
55
import { useEffect, useRef } from 'react';
66
import type { CSSMotionProps } from '../CSSMotion';

src/hooks/useStepQueue.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import useState from 'rc-util/lib/hooks/useState';
1+
import useState from '@rc-component/util/lib/hooks/useState';
22
import * as React from 'react';
33
import type { MotionStatus, StepStatus } from '../interface';
44
import {

src/util/motion.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import canUseDOM from 'rc-util/lib/Dom/canUseDom';
2-
import { MotionName } from '../CSSMotion';
1+
import canUseDOM from '@rc-component/util/lib/Dom/canUseDom';
2+
import type { MotionName } from '../CSSMotion';
33

44
// ================= Transition =================
55
// Event wrapper. Copy from react source code

tests/CSSMotion.spec.tsx

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ describe('CSSMotion', () => {
288288
});
289289

290290
describe('deadline should work', () => {
291+
// NOTE: only test for not crash here
292+
// Since React 19 not support `findDOMNode` anymore
293+
// the func call will not get real DOM node
291294
function test(name: string, Component: React.ComponentType<any>) {
292295
it(name, () => {
293296
const onAppearEnd = jest.fn();
@@ -839,10 +842,11 @@ describe('CSSMotion', () => {
839842
jest.resetAllMocks();
840843
});
841844

842-
it('calls findDOMNode when no refs are passed', () => {
845+
it('not crash when no refs are passed', () => {
843846
const Div = () => <div />;
847+
const cssMotionRef = React.createRef();
844848
render(
845-
<CSSMotion motionName="transition" visible>
849+
<CSSMotion motionName="transition" visible ref={cssMotionRef}>
846850
{() => <Div />}
847851
</CSSMotion>,
848852
);
@@ -851,7 +855,8 @@ describe('CSSMotion', () => {
851855
jest.runAllTimers();
852856
});
853857

854-
expect(ReactDOM.findDOMNode).toHaveBeenCalled();
858+
expect(cssMotionRef.current).toBeFalsy();
859+
expect(ReactDOM.findDOMNode).not.toHaveBeenCalled();
855860
});
856861

857862
it('does not call findDOMNode when ref is passed internally', () => {
@@ -868,11 +873,24 @@ describe('CSSMotion', () => {
868873
expect(ReactDOM.findDOMNode).not.toHaveBeenCalled();
869874
});
870875

871-
it('calls findDOMNode when refs are forwarded but not assigned', () => {
876+
it('support nativeElement of ref', () => {
872877
const domRef = React.createRef();
873-
const Div = () => <div />;
878+
const Div = React.forwardRef<
879+
{
880+
nativeElement: HTMLDivElement;
881+
},
882+
object
883+
>((props, ref) => {
884+
const divRef = React.useRef<HTMLDivElement>(null);
874885

875-
render(
886+
React.useImperativeHandle(ref, () => ({
887+
nativeElement: divRef.current!,
888+
}));
889+
890+
return <div {...props} ref={divRef} className="bamboo" />;
891+
});
892+
893+
const { container } = render(
876894
<CSSMotion motionName="transition" visible ref={domRef}>
877895
{() => <Div />}
878896
</CSSMotion>,
@@ -882,7 +900,8 @@ describe('CSSMotion', () => {
882900
jest.runAllTimers();
883901
});
884902

885-
expect(ReactDOM.findDOMNode).toHaveBeenCalled();
903+
expect(domRef.current).toBe(container.querySelector('.bamboo'));
904+
expect(ReactDOM.findDOMNode).not.toHaveBeenCalled();
886905
});
887906

888907
it('does not call findDOMNode when refs are forwarded and assigned', () => {

0 commit comments

Comments
 (0)