-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add: 프로젝트 캠프 1주차 리뷰 작성 * Update: last modified 날짜 추가 * Update: 수업 사진 추가 및 사진 alt text 수정 * Update: FontAwesomeIcon 대체 - 초기 렌더링 문제 방지 * Update: ProfileImage 숨기기 * Fix: 이미지 크기에 따른 모바일 화면 overflow 오류 해결 * Add: Next.js 프로젝트 캠프 2주차 내용 작성 * Add: 'nextjs' 태그 추가 * Update: 커버 이미지 변경 * Change: 폴더 날짜 변경 * Add: 이미지 추가 * Add: 프로젝트 캠프 3주차 리뷰 작성 * Update: 오탈자 수정 및 hydration 참고 링크 추가 * Update: auth 기본 설명 수정 * Add: 사용자 인증 내용 추가 * Update: 사용자 인증 내용 수정 * Change: 프로젝트 카테고리; Course -> Camp * Update: 앱 라우터 그룹 참고 내용 추가 * Change: 폴더 날짜 변경 * Pull (#11) * Writing (#10) * Add: 프로젝트 캠프 1주차 리뷰 작성 * Update: last modified 날짜 추가 * Update: 수업 사진 추가 및 사진 alt text 수정 * Update: FontAwesomeIcon 대체 - 초기 렌더링 문제 방지 * Update: ProfileImage 숨기기 * Fix: 이미지 크기에 따른 모바일 화면 overflow 오류 해결 * Add: Next.js 프로젝트 캠프 2주차 내용 작성 * Add: 'nextjs' 태그 추가 * Update: 커버 이미지 변경 * Change: 폴더 날짜 변경 * Add: 이미지 추가 * Add: 프로젝트 캠프 3주차 리뷰 작성 * Update: 오탈자 수정 및 hydration 참고 링크 추가 * Update: auth 기본 설명 수정 * Add: 사용자 인증 내용 추가 * Update: 사용자 인증 내용 수정 * Change: 프로젝트 카테고리; Course -> Camp * Update: 앱 라우터 그룹 참고 내용 추가 * Change: 폴더 날짜 변경 * Delete contents/2024-06-07 directory 중복 디렉토리 삭제 * Update: post table style * Add: 4주차 프로젝트 진행 리뷰 작성 * Update: 날짜 수정 * Update: 폴더 날짜 수정 * chore: change emoji * chore: add favicon * chore: change input checkbox * write: 프로젝트 캠프 5주차 리뷰 작성 * style: 다크 모드 적용 (#15) * Writing (#14) * chore: change emoji * chore: add favicon * chore: change input checkbox * write: 프로젝트 캠프 5주차 리뷰 작성 * [Style] useDarkMode 훅 추가 * [Style] flex 스타일 수정 * [Feat] 테마 토글 버튼 컴포넌트 추가 * [Style] prefer-color-scheme 스타일 적용 * chore * chore: 수정 * write: 오류 해결 과정 정리글 작성 * write: 프로젝트 캠프 6주차 진행 과정 리뷰 작성 * chore: update tag * style: update * write: dark-mode context
- Loading branch information
1 parent
67b1b8c
commit 5c7dd41
Showing
21 changed files
with
283 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
--- | ||
date: '2024-07-05 18:00:00' | ||
title: 'Prop `id` did not match from react-select when rendering in SSR' | ||
category: 'Next.js' | ||
tags: ['til', 'error-fix', 'ssr', 'react-select', 'id-not-match', 'hydration'] | ||
summary: 'SSR 환경에서 발생하게 되는 에러 해결하기' | ||
emoji: '⚠️' | ||
--- | ||
|
||
# Thrown Error | ||
|
||
## error message | ||
|
||
Next.js 프로젝트 내에서 즐겁게 개발을 하던 중 콘솔 창에서 에러를 발견했다. | ||
|
||
![콘솔창에서 발견해버린 Warning: Prop `id` did not match. Server: "react-selec-2-live-region" Client: "react-select-3-live-region"](./not-match-react-select-id-in-ssr-1.png) | ||
|
||
찾아보니 react-select 깃허브 레포지토리에서 같은 문제로 생성되었던 이슈 내용을 발견할 수 있었다. [관련 Issue#2629](https://github.com/JedWatson/react-select/issues/2629) | ||
|
||
![Issue#2629 on May 20, 2018](./not-match-react-select-id-in-ssr-1-1.png) | ||
|
||
## solve | ||
|
||
사실 위에서 추가한 관련 이슈 링크에서 연결된 글들을 읽어보면 해결책을 찾을 수 있는데, 여전히 해결책이 통하지 않는다는 이야기도 함께 보인다. 일단 위에서부터 읽어 내려오며 시도해 봤다. | ||
|
||
처음엔 작성한 Input.Select 컴포넌트에 id, 그다음엔 instanceId와 inputId까지 추가해 봤지만 오류가 사라지지 않았다. | ||
|
||
![첫번째 시도: Input.Select에 id, instanceId, inputId 속성 추가](./not-match-react-select-id-in-ssr-2.png) | ||
|
||
그리고 아래 이미지와 같이 다른 개발자가 관련 문제를 해결하고 [PR 한 내용](https://github.com/buildo/bento-design-system/pull/859)을 보게 되었다. | ||
|
||
!['https://github.com/buildo/bento-design-system/pull/859'에서 문제 해결을 위해 작성한 코드(File changed)](./not-match-react-select-id-in-ssr-3.png) | ||
|
||
바뀐 코드를 보면 컴포넌트에서 id 속성을 받아 react-select 컴포넌트에 전달하고 id 속성을 받아오지 않는 경우를 위해 `useId`를 사용하여 기본 id 값을 지정하고 있다. | ||
|
||
이와 마찬가지로 내 코드에도 반영하니 더 이상 오류 콘솔이 보이지 않는다. 👍 | ||
|
||
# Find Reasons | ||
|
||
## unique id value for select(input) | ||
|
||
오류 콘솔을 처리했지만 이러한 오류 발생의 이유를 이해해 보자면, 이슈에 달렸던 답변을 다시 한번 봐야 한다. | ||
|
||
![By default if no id is defined, we increment an instancePrefix as a global variable (i.e. react-select-1, react-select-2). We do this to ensure that if you have multiple selects on the same page, they aren't all referenced by the same Id.](not-match-react-select-id-in-ssr-1-2.png) | ||
|
||
> By default if no id is defined, we increment an instancePrefix as a global variable (i.e. react-select-1, react-select-2). We do this to ensure that if you have multiple selects on the same page, they aren't all referenced by the same Id. | ||
> 기본적으로 id가 정의되지 않은 경우에 전역 변수로 인스턴스 프리픽스를 증가시켜 _(이 값을 id에 정의)_ 동일한 페이지에서 여러 select 항목이 있는 경우 모두 동일한 id로 참조되지 않도록 합니다. | ||
HTML input 태그는 동일한 HTML 문서 내 같은 요소가 있는 것을 대비하여 id 속성과 name 속성을 전달받는다. 이를 이용하여 react-select에서는 재사용되는 Select 컴포넌트의 참조 오류가 나지 않도록 유일한 id 값(unique id)을 갖도록 하는데, 이를 위해 id 값이 없는 경우 자체적으로 전역 변수 instancePrefix를 이용하여 자동으로 값을 부여한다. | ||
|
||
이 과정에서 SSR 환경인 Next.js 하이드레이션이 발생하면 자동으로 id 값을 다시 부여한다. 이때 같은 요소에 대해 서버 사이드에서 가지고 있는 id와 클라이언트 사이드의 id와 일치하지 않게 되는 과정을 이해할 수 있다. 그렇기 때문에 화면에 react-select 컴포넌트가 하나여도 마찬가지로 해당 오류가 발생하는 것을 확인할 수 있는데, 이 때도 초기 렌더링 시에는 발생하지 않는 것처럼 보이지만 페이지를 새로고침하면 다시 오류를 볼 수 있다. | ||
|
||
## hydration | ||
|
||
이전에도 공부하며 내용을 정리하긴 했지만, 한 번 더 이해하고 넘어가자면, 하이드레이션(hydration)은 우리가 url을 통해 해당 페이지에 접근했을 때 서버 사이드에서 생성된 HTML 문서 내용(server component, client component 모두)을 먼저 빠르게 가져와 보여주고 사용자와 인터랙션을 위해 필요한 클라이언트 컴포넌트 부분을 클라이언트 사이드에서 생성하여 먼저 보여줬던 화면에 연결한다. | ||
|
||
이와 관련된 react 문서를 더 살펴볼 수 있다. | ||
|
||
- [`hydrateRoot`](https://react.dev/reference/react-dom/client/hydrateRoot) | ||
- [`react-dom/server`](https://react.dev/reference/react-dom/server) | ||
|
||
![hydrateRoot: `hydrateRoot` lets you display React components inside a browser DOM node whose HTML content was previously generated by `react-dom/server`.](./not-match-react-select-id-in-ssr-5.png) | ||
|
||
> `hydrateRoot` lets you display React components inside a browser DOM node whose HTML content was previously generated by `react-dom/server`. | ||
> `hydrateRoot`는 `react-dom/server`에서 사전에 생성한 HTML 컨텐츠가 들어있는 브라우저 DOM 내부에 React 컴포넌트를 표시할 수 있도록 합니다. | ||
react-select의 Select 컴포넌트는 클라이언트 컴포넌트로 사용해야 하기 때문에 이 컴포넌트를 사용하는 페이지에서 하이드레이션이 발생할 수밖에 없고 이 과정에서 id를 지정해 주지 않으면 위와 같은 오류가 발생하게 되는 것이다. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.