-
Notifications
You must be signed in to change notification settings - Fork 43
fix(stackflow): scope swipe-back vars to activity roots to cut style recalculation #1204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,5 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useCallbackRef } from "@radix-ui/react-use-callback-ref"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useCallback, useMemo, useRef, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useStack } from "@stackflow/react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useTopActivity } from "../private/useTopActivity"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export type SwipeBackState = "idle" | "swiping" | "canceling" | "completing"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -46,6 +46,7 @@ export interface MoveSwipeBackProps { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface EndSwipeBackProps {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function useGlobalInteraction() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const stack = useStack(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [swipeBackState, setSwipeBackState] = useState<SwipeBackState>("idle"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const swipeBackContextRef = useRef<SwipeBackContext>({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -56,103 +57,159 @@ export function useGlobalInteraction() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| velocity: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const stackRef = useRef<HTMLDivElement>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const swipeBackTargetsRef = useRef<HTMLElement[]>([]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const setSwipeBackContext = useCallback((ctx: SwipeBackContext) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackContextRef.current = ctx; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stackRef.current?.style.setProperty( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--swipe-back-displacement", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `${ctx.displacement.toString()}px`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stackRef.current?.style.setProperty( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--swipe-back-displacement-ratio", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ctx.displacementRatio.toString(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const resetSwipeBackVars = useCallback((element: HTMLElement) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.style.removeProperty("--swipe-back-displacement"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.style.removeProperty("--swipe-back-displacement-ratio"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.style.removeProperty("--swipe-back-target"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const setSwipeBackVar = useCallback((name: string, value: string) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackTargetsRef.current.forEach((element) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element.style.setProperty(name, value); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const applySwipeBackContext = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (ctx: SwipeBackContext) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackVar("--swipe-back-displacement", `${ctx.displacement.toString()}px`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackVar("--swipe-back-displacement-ratio", ctx.displacementRatio.toString()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [setSwipeBackVar], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const activities = stack.activities; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const updateSwipeBackTargets = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (nextActivities: typeof activities) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const stackElement = stackRef.current; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!stackElement) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackTargetsRef.current.forEach(resetSwipeBackVars); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackTargetsRef.current = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const topIndex = nextActivities.findIndex((activity) => activity.isTop); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const targets: HTMLElement[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (topIndex >= 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const topId = nextActivities[topIndex].id; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const topElement = stackElement.querySelector<HTMLElement>(`[data-activity-id="${topId}"]`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (topElement?.dataset["activityType"] === "full-screen") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| targets.push(topElement); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let index = topIndex - 1; index >= 0; index -= 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const behindElement = stackElement.querySelector<HTMLElement>( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `[data-activity-id="${nextActivities[index].id}"]`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (behindElement?.dataset["activityType"] === "full-screen") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| targets.push(behindElement); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const previousTargets = swipeBackTargetsRef.current; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| previousTargets.forEach((previousTarget) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!targets.includes(previousTarget)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resetSwipeBackVars(previousTarget); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackTargetsRef.current = targets; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| applySwipeBackContext(swipeBackContextRef.current); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [applySwipeBackContext, resetSwipeBackVars], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useLayoutEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| updateSwipeBackTargets(activities); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [activities, updateSwipeBackTargets]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const setSwipeBackContext = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (ctx: SwipeBackContext) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackContextRef.current = ctx; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| applySwipeBackContext(ctx); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [applySwipeBackContext], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const getSwipeBackEvents = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (props: SwipeBackProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackDisplacementRatioThreshold: displacementRatioThreshold = 0.4, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackVelocityThreshold: velocityThreshold = 1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSwipeBackStart, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSwipeBackMove, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSwipeBackEnd, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } = props; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const onSwipeStart = useCallbackRef(props.onSwipeBackStart); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const onSwipeMove = useCallbackRef(props.onSwipeBackMove); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const onSwipeEnd = useCallbackRef(props.onSwipeBackEnd); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const startSwipeBack = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ({ x0, t0 }: StartSwipeBackProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackContext({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| x0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displacement: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displacementRatio: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| velocity: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackState((prev) => (prev === "swiping" ? prev : "swiping")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSwipeStart?.(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [onSwipeStart], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const moveSwipeBack = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ({ x, t }: MoveSwipeBackProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const displacement = x - swipeBackContextRef.current.x0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const displacementRatio = displacement / window.innerWidth; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const velocity = displacement / (t - swipeBackContextRef.current.t0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackContext({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...swipeBackContextRef.current, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displacement, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displacementRatio, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| velocity, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackState((prev) => (prev === "swiping" ? prev : "swiping")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSwipeMove?.({ displacement, displacementRatio }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [onSwipeMove], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const endSwipeBack = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (_: EndSwipeBackProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const swiped = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackContextRef.current.displacementRatio > displacementRatioThreshold || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackContextRef.current.velocity > velocityThreshold; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (swiped) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stackRef.current?.style.setProperty("--swipe-back-target", "100%"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackState("completing"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stackRef.current?.style.setProperty("--swipe-back-target", "0"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackState("canceling"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSwipeEnd?.({ swiped }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [onSwipeEnd, displacementRatioThreshold, velocityThreshold], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const reset = useCallback(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const startSwipeBack = ({ x0, t0 }: StartSwipeBackProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackContext({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| x0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displacement: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displacementRatio: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| velocity: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackState((prev) => (prev === "swiping" ? prev : "swiping")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSwipeBackStart?.(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const moveSwipeBack = ({ x, t }: MoveSwipeBackProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const displacement = x - swipeBackContextRef.current.x0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const displacementRatio = displacement / window.innerWidth; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const velocity = displacement / (t - swipeBackContextRef.current.t0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackContext({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...swipeBackContextRef.current, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displacement, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displacementRatio, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| velocity, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackState((prev) => (prev === "swiping" ? prev : "swiping")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSwipeBackMove?.({ displacement, displacementRatio }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+163
to
+175
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0으로 나누기 가능성이 있습니다.
🛡️ 0으로 나누기 방어 코드 제안 const moveSwipeBack = ({ x, t }: MoveSwipeBackProps) => {
const displacement = x - swipeBackContextRef.current.x0;
const displacementRatio = displacement / window.innerWidth;
- const velocity = displacement / (t - swipeBackContextRef.current.t0);
+ const timeDelta = t - swipeBackContextRef.current.t0;
+ const velocity = timeDelta > 0 ? displacement / timeDelta : 0;
setSwipeBackContext({
...swipeBackContextRef.current,
displacement,
displacementRatio,
velocity,
});📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const endSwipeBack = (_: EndSwipeBackProps) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const swiped = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackContextRef.current.displacementRatio > displacementRatioThreshold || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| swipeBackContextRef.current.velocity > velocityThreshold; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (swiped) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackVar("--swipe-back-target", "100%"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackState("completing"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackVar("--swipe-back-target", "0"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackState("canceling"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSwipeBackEnd?.({ swiped }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const reset = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackContext({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| x0: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t0: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displacement: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| displacementRatio: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| velocity: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stackRef.current?.style.setProperty("--swipe-back-target", "0"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackVar("--swipe-back-target", "0"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setSwipeBackState("idle"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return useMemo( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| startSwipeBack, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| moveSwipeBack, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endSwipeBack, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reset, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [startSwipeBack, moveSwipeBack, endSwipeBack, reset], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| startSwipeBack, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| moveSwipeBack, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| endSwipeBack, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reset, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [setSwipeBackContext], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [setSwipeBackContext, setSwipeBackVar], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const topActivity = useTopActivity(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useLayoutEffect에 cleanup 함수가 없습니다.
컴포넌트 언마운트 시 타겟 엘리먼트에 설정된 CSS 변수들(
--swipe-back-displacement,--swipe-back-displacement-ratio,--swipe-back-target)이 정리되지 않습니다.🧹 cleanup 함수 추가 제안
useLayoutEffect(() => { updateSwipeBackTargets(activities); + return () => { + swipeBackTargetsRef.current.forEach(resetSwipeBackVars); + swipeBackTargetsRef.current = []; + }; }, [activities, updateSwipeBackTargets]);🤖 Prompt for AI Agents