Next.js state 변경 UI 끊기는 문제 해결 (framer-motion 적용)

JongMin Seong·2024년 12월 3일
0

글을 쓴 배경

현재 Next.js로 예술 작품을 보여주는 프로젝트를 진행 중인데
보여지는 그림이 달라지면 끊어지는 느낌을 받는다. 사용자 경험을 위해서
개선이 필요하다고 생각이 들었고 찾아본 결과 framer-motion을 사용하는 것이 좋을거 같기에 사용하게 되었다.

프로젝트 문제

UI가 끊어지는 문제점 발생
UI 문제점

해결법

  1. framer-motion 적용 => 적용해서 부드럽게 넘어가지만 비슷하게 끊어지는 현상 발생 (그림을 보여주는 compoent가 state가 비어져 있기에 발생한 문제로 확인)
  2. 부모 component에 min height 설정 => 문제점 해결

코드

// MCQView.tsx

const MCQView = ({ attribute, currentAttributeIndex, handelNextMCQ }: MCQReaderViewProps) => {

// ...
    const handleImageClick = (answerId: string) => {
        if (!isSubmitted) {
            // setSelectedIndex(index);
            handleReaderSelectAnswer(answerId);
        }
    };

    // TODO 틀렸을 경우 어떻게 할지 의논 필요
    const handleTryAgain = () => {
        console.log(`isSubmitted: ${isSubmitted}`);

        cleatSubmitState();
        handelNextMCQ();
    };

    return (
        // display size 마다 minHeight을 정하여 깜빡임 형상 방지 (모바일 크기만 신경쓰면 됨)
        <div className="p-4 rounded-md shadow bg-ggrimBeige2" style={{ minHeight: '744px' }}>
            <h3 className="text-xl font-bold text-gray-800 mb-6">{question}</h3>
            <motion.div
                key={currentAttributeIndex}
                initial={{ opacity: 0, x: 50 }}
                animate={{ opacity: 1, x: 0 }}
                exit={{ opacity: 0, x: -50 }}
                // transition={{ duration: 1.0 }}
                transition={{
                    duration: 0.7, // 애니메이션이 총 걸리는 시간
                    delay: 0.3, // 처음 애니메이션 delay
                    delayChildren: 0.3,
                }}
            >
                {errorMessage && <ErrorMessage message={errorMessage} />}
                <div className="grid md:grid-cols-2 gap-4 sm:grid-cols-1">
                    {displayPaintings.map((painting, index) => (
                        <div
                            key={painting.id}
                            className={`flex flex-col items-center p-4 rounded-md ${
                                isSubmitted
                                    ? painting.id === answerKey
                                        ? 'bg-green-300'
                                        : 'bg-red-300'
                                    : 'bg-white'
                            } shadow-md ${
                                readerSelectedAnswer === painting.id
                                    ? 'border-4 border-primary'
                                    : ''
                            }`}
                            onClick={() => handleImageClick(painting.id)}
                        >
                            <img
                                src={painting.image}
                                alt={`Answer ${index}`}
                                className={`w-50 h-auto max-h-[250px] max-w-full  mb-2 ${
                                    readerSelectedAnswer === painting.id
                                        ? 'ring-4 ring-primary'
                                        : ''
                                }`}
                            />
                        </div>
                    ))}
                </div>
            </motion.div>
            <div className="flex justify-end items-center">
                <SubmissionFeedback
                    isCorrect={isCorrect}
                    isSubmitted={isSubmitted}
                    handleSubmit={handleSubmit}
                    handleHintButtonClick={handleHintButtonClick}
                    handleClearSubmission={handleClearSubmission}
                    handleNextMCQ={handelNextMCQ}
                    handelTryAgain={handleTryAgain}
                    showHintButton={false}
                />
            </div>
        </div>
    );
};



적용 결과

결론

framer-motion을 사용하면 될거라는 생각에 적용 방법과 사용 법을 공부를 하였다. 하지만 근본적인 원인은 랜더링 중 state값이 변화되면서 자식 component의 크기가 작아져서 발생하는 문제 였다.
좀 더 문제의 근본적인 원인을 파악하는 연습이 필요함을 느꼈다
(framer-motion을 사용하는게 부드럽게 전화되기에 삭제하지 않았다, )

profile
개발 공부 기록

0개의 댓글