Skip to content
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

[Fix] Transition 버벅임 문제 해결 #177

Merged
merged 4 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions client/src/features/CasperShowCase/CasperCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ export function CasperCards({ cardList }: CasperCardsProps) {
const itemWidth = CASPER_CARD_SIZE[CASPER_SIZE_OPTION.SM].CARD_WIDTH;
const gap = 40;
const totalWidth = (itemWidth + gap) * visibleCardCount;
const paddedCasperWidth = CASPER_CARD_SIZE[CASPER_SIZE_OPTION.SM].CARD_WIDTH + gap;

const isEndTopCard = (latestX: number) => {
return latestX <= -totalWidth;
return latestX <= -paddedCasperWidth;
};
const isEndBottomCard = (latestX: number) => {
return latestX >= 0;
Expand All @@ -39,15 +40,15 @@ export function CasperCards({ cardList }: CasperCardsProps) {
initialX={0}
gap={gap}
diffX={-totalWidth}
visibleCardCount={visibleCardCount}
visibleCardCount={visibleCardCount + 1}
isEndCard={isEndTopCard}
/>
<TransitionCasperCards
cardList={bottomCardList}
initialX={-totalWidth}
initialX={-paddedCasperWidth}
gap={gap}
diffX={totalWidth}
visibleCardCount={visibleCardCount}
visibleCardCount={visibleCardCount + 1}
isEndCard={isEndBottomCard}
isReverseCards
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { useState } from "react";
import { memo, useState } from "react";
import { CASPER_CARD_SIZE, CASPER_SIZE_OPTION } from "@/constants/CasperCustom/casper";
import { CasperFlipCard } from "@/features/CasperCustom/CasperCard/CasperFlipCard";
import type { CasperCardType } from "@/types/casper";

interface TransitionCasperCardItemProps {
cardItem: CasperCardType;
id: string;
id: number;
stopAnimation?: () => void;
startAnimation?: () => void;
}

export function TransitionCasperCardItem({
export const TransitionCasperCardItem = memo(function TransitionCasperCardItem({
cardItem,
id,
stopAnimation,
Expand Down Expand Up @@ -41,4 +41,4 @@ export function TransitionCasperCardItem({
<CasperFlipCard card={cardItem} size={CASPER_SIZE_OPTION.SM} isFlipped={isFlipped} />
</li>
);
}
});
77 changes: 36 additions & 41 deletions client/src/features/CasperShowCase/TransitionCasperCards.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { AnimatePresence, type ResolvedValues, motion, useAnimation } from "framer-motion";
import { CARD_TRANSITION } from "@/constants/CasperShowCase/showCase";
import type { CasperCardType } from "@/types/casper";
Expand All @@ -24,19 +24,19 @@ export function TransitionCasperCards({
isReverseCards = false,
}: TransitionCasperCardsProps) {
const isAnimated = visibleCardCount <= cardList.length;
const expandedCardList = useMemo(() => [...cardList, ...cardList, ...cardList], [cardList]);

const containerRef = useRef<HTMLUListElement>(null);
const transitionControls = useAnimation();

const [x, setX] = useState<number>(initialX);
const [visibleCardListIdx, setVisibleCardListIdx] = useState(0);
const [visibleCardList, setVisibleCardList] = useState<CasperCardType[]>([]);
const [popCardIdx, setPopCardIdx] = useState(cardList.length - 1);

const startAnimation = useCallback(
(x: number) => {
transitionControls.start({
x: [x, x + diffX * 2],
transition: CARD_TRANSITION(visibleCardCount * 2),
x: [x, x + diffX],
transition: CARD_TRANSITION(visibleCardCount),
});
},
[visibleCardCount, transitionControls]
Expand All @@ -51,41 +51,40 @@ export function TransitionCasperCards({
}
}, [transitionControls, containerRef]);

const visibleCardList = useMemo(() => {
const list = expandedCardList.slice(
visibleCardListIdx,
visibleCardListIdx + visibleCardCount * 2
);
useEffect(() => {
const currentCardList = cardList.slice(0, visibleCardCount);
const sortedCards = isReverseCards ? currentCardList.reverse() : currentCardList;
setVisibleCardList(sortedCards);
startAnimation(x);
}, []);

if (isAnimated && isReverseCards) {
return list.reverse();
const updateVisibleCards = (prevCards: CasperCardType[]) => {
const updatedCards = [...prevCards];
const lastCardIdx = (popCardIdx + 1) % cardList.length;

if (isReverseCards) {
updatedCards.pop();
updatedCards.unshift(cardList[lastCardIdx]);
} else {
updatedCards.shift();
updatedCards.push(cardList[lastCardIdx]);
}

return isAnimated ? list : cardList;
}, [
isReverseCards,
expandedCardList,
cardList,
isAnimated,
visibleCardCount,
visibleCardListIdx,
]);
setPopCardIdx(lastCardIdx);

useEffect(() => {
startAnimation(x);
}, []);
return updatedCards;
};

const handleUpdateAnimation = (latest: ResolvedValues) => {
if (isEndCard(parseInt(String(latest.x)))) {
let nextIdx = visibleCardListIdx + visibleCardCount;
const currentX = parseInt(String(latest.x), 10);

// 만약 nextIdx가 cardList의 길이를 초과하면 배열의 처음부터 다시 index를 카운트하도록 함
if (nextIdx >= cardList.length) {
nextIdx = nextIdx % cardList.length;
}
if (isEndCard(currentX)) {
setVisibleCardList((prevCards) => {
const updatedCards = updateVisibleCards(prevCards);
return updatedCards;
});

setVisibleCardListIdx(nextIdx);
startAnimation(initialX);
startAnimation(isReverseCards ? initialX : initialX);
}
};

Expand All @@ -99,24 +98,20 @@ export function TransitionCasperCards({
style={{ gap: `${gap}px` }}
onUpdate={handleUpdateAnimation}
>
{visibleCardList.map((card, idx) => (
{visibleCardList.map((card) => (
<TransitionCasperCardItem
key={`${card.id}-${idx}`}
key={card.id}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key에 index까지 추가해두면 배열에 새로운 카드가 추가될 때마다 key값이 바껴서 모든 배열이 리렌더링이 발생해서 idx는 삭제,,

cardItem={card}
id={`${card.id}-${idx}`}
id={card.id}
stopAnimation={stopAnimation}
startAnimation={() => startAnimation(x)}
/>
))}
</motion.ul>
) : (
<ul className="flex w-screen justify-center" style={{ gap: `${gap}px` }}>
{visibleCardList.map((card, idx) => (
<TransitionCasperCardItem
key={`${card.id}-${idx}`}
cardItem={card}
id={`${card.id}-${idx}`}
/>
{cardList.map((card) => (
<TransitionCasperCardItem key={card.id} cardItem={card} id={card.id} />
))}
</ul>
)}
Expand Down
Loading