Hydration 에러: styled-components와 framer-motion동시 사용시 props가 강제로 넘어가면서 생긴 복합적 문제 해결하기

Description: HeroBanner 구현 중 styled-components와 framer-motion 결합으로 발생한 Hydration 에러를 분석하고, Next.js의 서버 렌더링과 클라이언트 DOM, 가상 DOM 간의 문제를 학습하며 해결한 과정을 기록합니다

현재 노트: KR-210.00 a Hydration 에러: styled-components와 framer-motion동시 사용시 props가 강제로 넘어가면서 생긴 복합적 문제 해결하기
상위 분류: KR-210 렌더링 및 UI or UX

#React_Next #React #styled_comonents #framer_motion

Hydration 에러: styled-components와 framer-motion동시 사용시 props가 강제로 넘어가면서 생긴 복합적 문제 해결하기

배경

HeroBanner컴포넌트를 만드는 과정에서 따로 따로 사용시 문제가 없는 두 개의 라이브러리를 동시에 쓰면서 발생하는 복합적인 문제가 발생하였습니다. 이 과정에서 Hydration 개념 학습 및 Next의 서버렌더링에서 최종 클라이언트 DOM까지의 과정 학습. 그리고 가상 DOM에서의 렌더링 문제를 학습하여 최종적으로 문제를 해결하기까지의 과정을 작성합니다

완성 결과

에러로그

Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used

See more info here: https://nextjs.org/docs/messages/react-hydration-error

+ bgcolor="#FFD700"
- bgcolor={null}
+ Page 1 Content

처음 파악한 원인 currentIndex 값의 불일치로 인한 hydration error

  1. 클라이언트에서만 동작하는 로직:
    • 타이머(setInterval)와 같은 로직은 클라이언트에서만 동작하며, 이는 서버에서는 실행되지 않습니다.
    • 브라우저가 Hydration을 완료하기 전에 상태 업데이트가 발생하면 불일치가 생깁니다.
      내 해석 : 서버에서는 useEffect가 실행이안되서 항상 currentIndex가 0인데, 클라이언트에서는 5초마다 계속 바뀌닌까 생기는 에러

해결 시도-> 중요한 것은 currentIndex의 서버측과 클라이언트측의 불일치
서버와 클라이언트 간의 초기 상태 동기화가 필요

좀 더 탐색

이 경고는 React가 클라이언트에서 Hydration 과정 중에 서버에서 생성한 HTML과 일치하지 않는 DOM을 발견했을 때 발생하는 에러
내 해석: 서버에서 에러를 반환하는게 아니라, 서버는 html만들고 끝 신경 안씀. 즉 만약 currentIndex가 달리진다 하더라도, 크게 문제가 안됨.
use client 선언으로 ssr렌더링이 되지 않아서 이 원인으로 hydration 에러가 발생하는 것은 이상함

  1. 서버는 html반환
  2. 클라이언트 에서 hydration시작
  3. 클라이언트 에서 hydration 중
  4. hydration이 끝남

최종원인 html에 없는 backgroundColor라는 custom props를 강제로 넘기면서 발생

styled-components와 React DOM의 상호작용에서 props가 DOM 속성으로 전달되면서 문제가 발생

특히 bakgroundColor라는 없는 props를 DOM에 넘기려고하면서 생기는 문제였음을 파악
더 근본적인 원인 styled-componets와 framer-motion간의 복합한 문제

내 해석: 보통 styled-componet의 props는 css내부처리로만 잘 사용되는데, framer-motion이랑 엮어서 사용하다보니 framer-motion의 경우 DOM에 props를 작성하게 되면서 생긴 문제같음. 왜냐하면 애니메이션이다보니 직접 DOM을 조작해야해서 기본적으로 DOM을 조작하기위해 props를 넘기는듯.

해결

에러 발생 시

구분 서버 HTML 렌더링 결과 React 가상 DOM 클라이언트 DOM
bgColor null #FFD700 없음 (DOM 속성으로 포함되지 않음)
style background-color: #FFD700 (CSS로 처리됨) backgroundColor: #FFD700 (CSS로 처리됨) background-color: #FFD700 (CSS로 처리됨)

해결 후

구분 서버 HTML 렌더링 결과 React 가상 DOM 클라이언트 DOM
$backgroundColor 없음 (DOM 속성으로 전달되지 않음) 없음 (React DOM에서 props로 처리되지 않음) 없음 (DOM에 포함되지 않음)
style background-color: #FFD700 (CSS로 처리됨) backgroundColor: #FFD700 (CSS로 처리됨) background-color: #FFD700 (CSS로 처리됨)
// 문제 해결전 props.bgColor사용
const Slide = styled(motion.div)`
...
  background-color: ${(props) =>
    props.bgColor || "#f5f5f5"};
  font-size: 24px;
`;

// 문제 해결 후 props.$backgroundColor로 변경
const Slide = styled(motion.div)`
...f
  background-color: ${(props) =>
    props.$backgroundColor || "#f5f5f5"}; /* $로 프롭스를 CSS 처리 */
  font-size: 24px;
`;


배운점