[트러블슈팅] react hydration 오류

ws·2024년 11월 26일

Coworkers

목록 보기
4/5

오류

문제 발생 컴포넌트
  • DatePicker

export function DatePicker({ mode }: DatePickerProps) {


const { selectedDate, setSelectedDate } = useTaskStore();
const [date, setDate] = React.useState<Date>();
  

...

const tomorrow = new Date(selectedDate);

tomorrow.setDate(tomorrow.getDate() + 1);

	setSelectedDate(tomorrow);

};


...
  

return (

<div className="flex items-center gap-3">

{mode === 'selector' && (

<>

<p className="text-xl-medium text-primary">

dfasdfsd

{selectedDate.toString()}

{/* {selectedDate

? formatKoreanDate(selectedDate)

: '날짜를 선택해주세요'} */}

</p>

<div className="flex items-center gap-2">

<Button

variant="secondary"

className={cn(

'h-6 w-6 text-lg-medium text-primary',

'bg-secondary hover:bg-interaction-hover',

'active:bg-interaction-pressed',

'rounded-full'

)}

onClick={handlePrevDate}

>

<ChevronLeftIcon className="h-3 w-3" />

</Button>

<Button

variant="secondary"

className={cn(

'h-6 w-6 text-lg-medium text-primary',

'bg-secondary hover:bg-interaction-hover',

'active:bg-interaction-pressed',

'rounded-full'

)}

onClick={handleNextDate}

>

<ChevronRightIcon className="h-1 w-1" />

</Button>

</div>

</>

)}

<Popover>

<PopoverTrigger asChild>

{mode === 'input' ? (

<Button

variant="outline"

className={cn(

'w-full justify-start rounded-xl py-[1.5rem] font-pretendard',

'text-left text-lg-regular text-primary',

'bg-secondary hover:bg-tertiary active:bg-tertiary',

'border-primary hover:border-interaction-hover',

!date && 'text-default'

)}

>

<CalendarIcon className="mr-2 h-4 w-4" />

{date ? format(date, 'PPP') : <span>날짜를 선택해주세요</span>}

</Button>

) : (

<Button

variant="default"

className={cn(

'h-8 w-8 rounded-full bg-secondary',

'hover:bg-interaction-focus active:bg-interaction-pressed'

)}

>

<CalendarIcon className={cn('h-4 w-4 text-icon-primary')} />

</Button>

)}

</PopoverTrigger>

<PopoverContent className="w-auto rounded-xl p-0">

<Calendar

mode="single"

selected={date}

onSelect={

mode === 'selector'

? (value) => setSelectedDate(value as Date)

: (value) => setDate(value as Date)

}

initialFocus

/>

</PopoverContent>

</Popover>

{mode === 'input' && (

<input

type="text"

value={date?.toISOString()}

className="hidden"

disabled

/>

)}

</div>

);

}
오류 메시지 확인
  • 파이어폭스 브라우저
# Unhandled Runtime Error

Error: Text content does not match server-rendered HTML. See more info here: [https://nextjs.org/docs/messages/react-hydration-error](https://nextjs.org/docs/messages/react-hydration-error)

Text content did not match. Server: "Sat Oct 19 2024 11:08:38 GMT+0900 (대한민국 표준시)" Client: "Sat Oct 19 2024 11:08:39 GMT+0900 (대한민국 표준시)"

## Call Stack

React

### ./node_modules/scheduler/cjs/scheduler.development.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1904:1)

Next.js

React

### ./node_modules/scheduler/index.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1915:1)

Next.js

React

### ./node_modules/react-dom/cjs/react-dom.development.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1827:1)

Next.js

React

### ./node_modules/react-dom/index.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1849:1)

Next.js

React

### ./node_modules/react-dom/client.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1838:1)

Next.js

### <unknown>

../src/client/next-dev.ts

Next.js

### <unknown>

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1965:53)

### <unknown>

webpackJsonpCallback@http://localhost:3000/_next/static/chunks/webpack.js (1291:46)

### <unknown>

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (9:61)


---


# Unhandled Runtime Error

Error: Hydration failed because the initial UI does not match what was rendered on the server. See more info here: [https://nextjs.org/docs/messages/react-hydration-error](https://nextjs.org/docs/messages/react-hydration-error)

Text content did not match. Server: "Sat Oct 19 2024 11:08:38 GMT+0900 (대한민국 표준시)" Client: "Sat Oct 19 2024 11:08:39 GMT+0900 (대한민국 표준시)"

## Call Stack

React

### ./node_modules/scheduler/cjs/scheduler.development.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1904:1)

Next.js

React

### ./node_modules/scheduler/index.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1915:1)

Next.js

React

### ./node_modules/react-dom/cjs/react-dom.development.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1827:1)

Next.js

React

### ./node_modules/react-dom/index.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1849:1)

Next.js

React

### ./node_modules/react-dom/client.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1838:1)

Next.js

### <unknown>

../src/client/next-dev.ts

Next.js

### <unknown>

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1965:53)

### <unknown>

webpackJsonpCallback@http://localhost:3000/_next/static/chunks/webpack.js (1291:46)

### <unknown>

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (9:61)


--------

# Unhandled Runtime Error

Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.

## Call Stack

React

### ./node_modules/scheduler/cjs/scheduler.development.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1904:1)

Next.js

React

### ./node_modules/scheduler/index.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1915:1)

Next.js

React

### ./node_modules/react-dom/cjs/react-dom.development.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1827:1)

Next.js

React

### ./node_modules/react-dom/index.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1849:1)

Next.js

React

### ./node_modules/react-dom/client.js

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1838:1)

Next.js

### <unknown>

../src/client/next-dev.ts

Next.js

### <unknown>

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (1965:53)

### <unknown>

webpackJsonpCallback@http://localhost:3000/_next/static/chunks/webpack.js (1291:46)

### <unknown>

file:/Users/wonsik/Documents/workspace/codeit/coworkers/.next/static/chunks/main.js (9:61)

원인

오류 메시지 확인
  • Unhandled Runtime Error 발생
  • 오류 메시지 확인 결과, Text 내용이 서버와 맞지 않아 react hydration 오류가 발생했습니다.
  • 시간에 관련된 요소의 내용이 서버에서는 "Sat Oct 19 2024 11:08:38 GMT+0900 (대한민국 표준시)", 클라이언트에서는 "Sat Oct 19 2024 11:08:39 GMT+0900 (대한민국 표준시)" 로 서버에서 렌더링된 시간과 클라이언트에서 렌더링한 시간 사이의 차이로 HTML 렌더링 내용이 같지 않아 리액트 하이드레이션 오류가 발생했습니다.
hydration
  • 일반적으로 React 는 CSR 방식으로 UI 를 그립니다. 0921_fin_01.jpg

  • Next.js 는 기본적으로 컴포넌트를 프리 렌더링합니다. 생성된 HTML 은 해당 컴포넌트에 필요한 최소한의 자바스크립트 코드와 연결되고, 브라우저가 페이지를 로드하면 자바스크립트 코드가 인터랙티브하게 만들어집니다. 이 과정을 hydration 이라고 합니다.

  • Next.js 에서는 두 가지의 프리 렌더링을 제공합니다.
    - Static Generation
    - 프리 렌더링 결과를 빌드 타임에 HTML 로 생성합니다.
    - ISR 방식을 활용하면 배포한 이후에도 HTML 을 생성하거나 업데이트할 수 있습니다.
    - Server Side Rendering
    - 페이지를 요청하면 HTML 을 생성하고 hyration 합니다.

hydration mismatch
  • react 를 통해 렌더링될 최초의 결과물이 hyration 할 html 과 반드시 일치해야 합니다.
  • 시간과 관련된 요소의 경우, 서버에서 렌더링된 시간과 클라이언트에서 렌더링한 시간이 달라져 hydration mismatch 오류를 발생시킵니다.

해결

해결 방법
  1. useEffect 를 사용하여 클라이언트에서만 실행
    • 서버, 클라이언트 측에서 동일한 내용을 렌더링하도록 해서 하이드레이션 불일치를 방지합니다.
    • isClient 상태를 useEffect 에서 true 로 만들어 클라이언트에서만 렌더링하는 방법입니다.
  2. 특정 컴포넌트에서 SSR 비활성화
    • Next.js 에서는 특정 컴포넌트에서 프리렌더링을 비활성화할 수 있어 하이드레이션 불일치를 방지할 수 있습니다.
  3. suppressHydrationWarning 사용
    • 시간 정보같이 서버와 클라이언트 간 내용이 불가피하게 다를 경우, 요소에 suppressHydrationWarning 을 추가하여 경고 메시지를 비활성화할 수 있습니다.
해결 방법 적용
  • 이번에 발생한 오류는 시간이 달라 발생한 오류이므로 해결 방법 3 번을 사용하여 해결할 수 있습니다.
  • 해당 요소에 suppressHydrationWarning 를 추가하여 경고 메시지를 비활성화 함으로써 해결했습니다.

참고

https://nextjs.org/docs/messages/react-hydration-error
https://react.dev/reference/react-dom/hydrate#suppressing-unavoidable-hydration-mismatch-errors
https://blog.hwahae.co.kr/all/tech/13604
https://velog.io/@juurom/TIL-react-hydration-error-%EC%9B%90%EC%9D%B8-%EB%B0%8F-%ED%95%B4%EA%B2%B0%EB%B0%A9%EB%B2%95-feat.-react-calendar

0개의 댓글