Skip to content

Commit 942a253

Browse files
author
liaoxuan
committed
feat: optimize performance
1 parent aa9be57 commit 942a253

File tree

4 files changed

+55
-72
lines changed

4 files changed

+55
-72
lines changed

lib/PullToRefreshify.tsx

Lines changed: 15 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { getScrollTop } from "./utils/getScrollTop";
88
import type { PullStatus, PullToRefreshifyProps } from "./types";
99
import { Events } from "./utils/events";
1010

11-
export function PullToRefreshify({
11+
export const PullToRefreshify = ({
1212
className,
1313
style,
1414
animationDuration = 300,
@@ -23,64 +23,38 @@ export function PullToRefreshify({
2323
prefixCls = "pull-to-refreshify",
2424
renderText,
2525
children,
26-
}: PullToRefreshifyProps) {
27-
const { ref: pullRef, scrollParent } = useScrollParent();
26+
}: PullToRefreshifyProps) => {
27+
const [pullRef, scrollParentRef] = useScrollParent();
2828
const unmountedRef = useUnmountedRef();
29-
const [{ offsetY, duration, status }, setState] = useState<{
30-
duration: number;
31-
offsetY: number;
32-
status: PullStatus;
33-
}>(
29+
const [[offsetY, duration, status], setState] = useState<
30+
[number, number, PullStatus]
31+
>(
3432
refreshing
35-
? {
36-
duration: animationDuration,
37-
offsetY: headHeight,
38-
status: "refreshing",
39-
}
40-
: {
41-
offsetY: 0,
42-
duration: 0,
43-
status: "normal",
44-
}
33+
? [headHeight, animationDuration, "refreshing"]
34+
: [0, 0, "normal"]
4535
);
4636

4737
const dispatch = (status: PullStatus, dragOffsetY = 0) => {
4838
switch (status) {
4939
case "pulling":
5040
case "canRelease":
51-
setState({
52-
status: status,
53-
duration: 0,
54-
offsetY: dragOffsetY,
55-
});
41+
setState([dragOffsetY, 0, status]);
5642
break;
5743

5844
case "refreshing":
59-
setState({
60-
status: status,
61-
duration: animationDuration,
62-
offsetY: headHeight,
63-
});
45+
setState([headHeight, animationDuration, status]);
6446
break;
6547

6648
case "complete":
67-
setState({
68-
status: status,
69-
duration: animationDuration,
70-
offsetY: headHeight,
71-
});
49+
setState([headHeight, animationDuration, status]);
7250
if (unmountedRef.current) return;
7351
setTimeout(() => {
7452
dispatch("normal");
7553
}, completeDelay);
7654
break;
7755

7856
default:
79-
setState({
80-
status: status,
81-
duration: animationDuration,
82-
offsetY: 0,
83-
});
57+
setState([0, animationDuration, status]);
8458
}
8559
};
8660

@@ -90,15 +64,15 @@ export function PullToRefreshify({
9064
}, [refreshing]);
9165

9266
// Handle darg events
93-
const { ref: dragRef } = useDrag({
67+
const dragRef = useDrag({
9468
onDragMove: (event, { offsetY: dragOffsetY }) => {
9569
if (
9670
// Not set onRefresh event
9771
!onRefresh ||
9872
// Pull up
9973
dragOffsetY <= 0 ||
10074
// Not scrolled to top
101-
(dragOffsetY > 0 && getScrollTop(scrollParent) > 0) ||
75+
(dragOffsetY > 0 && getScrollTop(scrollParentRef.current) > 0) ||
10276
// Refreshing state has been triggered
10377
["refreshing", "complete"].includes(status) ||
10478
disabled
@@ -191,4 +165,4 @@ export function PullToRefreshify({
191165
</div>
192166
</div>
193167
);
194-
}
168+
};

lib/utils/useDrag.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ function isMouseEvent(e: DragEvent): e is MouseEvent {
2222
return e && !("touches" in e);
2323
}
2424

25-
export function useDrag({
25+
export const useDrag = ({
2626
onDragStart,
2727
onDragMove,
2828
onDragEnd,
2929
}: {
3030
onDragStart?: (event: DragEvent, dragState: DragState) => void;
3131
onDragMove?: (event: DragEvent, dragState: DragState) => boolean;
3232
onDragEnd?: (event: DragEvent, dragState: DragState) => void;
33-
}) {
33+
}) => {
3434
const ref = useRef<any>(null);
3535
const onDragStartRef = useLatest(onDragStart);
3636
const onDragMoveRef = useLatest(onDragMove);
@@ -41,9 +41,7 @@ export function useDrag({
4141

4242
if (!dragEl) return;
4343

44-
let dragState = {
45-
...initialDragState,
46-
};
44+
let dragState: DragState;
4745
let isStart = false;
4846

4947
const initDragState = () => {
@@ -52,6 +50,8 @@ export function useDrag({
5250
};
5351
};
5452

53+
initDragState();
54+
5555
const handleTouchstart = ((event: DragEvent) => {
5656
isStart = true;
5757
initDragState();
@@ -123,5 +123,5 @@ export function useDrag({
123123
// eslint-disable-next-line react-hooks/exhaustive-deps
124124
}, []);
125125

126-
return { ref };
127-
}
126+
return ref;
127+
};

lib/utils/useFirstMountState.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useRef } from "react";
22

3-
export function useFirstMountState(): boolean {
3+
export const useFirstMountState = (): boolean => {
44
const isFirst = useRef(true);
55

66
if (isFirst.current) {
@@ -10,4 +10,4 @@ export function useFirstMountState(): boolean {
1010
}
1111

1212
return isFirst.current;
13-
}
13+
};

lib/utils/useScrollParent.ts

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { useEffect, useRef, useState } from "react";
1+
import { useEffect, useRef } from "react";
22
import { getScrollTop } from "./getScrollTop";
33
import { Events } from "./events";
44

5-
function getScrollParent(node: Element) {
5+
const getScrollParent = (node: Element) => {
66
while (node && node.parentNode && node.parentNode !== document.body) {
77
const computedStyle = window.getComputedStyle(node);
88
if (
@@ -19,42 +19,39 @@ function getScrollParent(node: Element) {
1919
}
2020

2121
return window;
22-
}
22+
};
2323

24-
export function useScrollParent() {
25-
const ref = useRef<any>();
26-
const [scrollParent, setScrollParent] =
27-
useState<ReturnType<typeof getScrollParent>>(window);
24+
export const useScrollParent = () => {
25+
const pullRef = useRef<any>();
26+
const touchstartYRef = useRef(0);
27+
const scrollParentRef = useRef<ReturnType<typeof getScrollParent>>(window);
28+
const unbindScrollParentEvents = useRef(() => {});
2829

29-
// eslint-disable-next-line react-hooks/exhaustive-deps
30-
useEffect(() => {
31-
setScrollParent(getScrollParent(ref.current));
32-
});
33-
34-
// Handle the scroll parent's touch events
35-
useEffect(() => {
36-
let touchstartY = 0;
30+
const bindScrollParentEvents = (
31+
scrollParent: ReturnType<typeof getScrollParent>
32+
) => {
33+
touchstartYRef.current = 0;
3734

3835
const handleTouchstart = ((event: TouchEvent) => {
3936
const touch = event.touches[0];
40-
touchstartY = touch.pageY;
37+
touchstartYRef.current = touch.pageY;
4138
}) as EventListener;
4239

4340
const handleTouchmove = ((event: TouchEvent) => {
4441
const touch = event.touches[0];
4542
const currentY = touch.pageY;
4643
if (
47-
currentY - touchstartY > 0 &&
44+
currentY - touchstartYRef.current > 0 &&
4845
event.cancelable &&
4946
getScrollTop(scrollParent) === 0 &&
50-
ref.current?.contains(event.target)
47+
pullRef.current?.contains(event.target)
5148
) {
5249
event.preventDefault();
5350
}
5451
}) as EventListener;
5552

5653
const handleTouchend = (() => {
57-
touchstartY = 0;
54+
touchstartYRef.current = 0;
5855
}) as EventListener;
5956

6057
Events.on(scrollParent, "touchstart", handleTouchstart);
@@ -68,7 +65,19 @@ export function useScrollParent() {
6865
Events.off(scrollParent, "touchend", handleTouchend);
6966
Events.off(scrollParent, "touchcancel", handleTouchend);
7067
};
71-
}, [scrollParent]);
68+
};
69+
70+
// eslint-disable-next-line react-hooks/exhaustive-deps
71+
useEffect(() => {
72+
const nextScrollParent = getScrollParent(pullRef.current);
73+
74+
if (nextScrollParent !== scrollParentRef.current) {
75+
unbindScrollParentEvents.current();
76+
unbindScrollParentEvents.current =
77+
bindScrollParentEvents(nextScrollParent);
78+
scrollParentRef.current = nextScrollParent;
79+
}
80+
});
7281

73-
return { ref, scrollParent };
74-
}
82+
return [pullRef, scrollParentRef] as const;
83+
};

0 commit comments

Comments
 (0)