2024.07.05.
Prop `id` did not match from react-select when rendering in SSR
Next.js

til / error-fix / ssr / react-select / id-not-match / hydration

Thrown Error

error message

Next.js 프로젝트 내에서 즐겁게 개발을 하던 중 콘솔 창에서 에러를 발견했다.

콘솔창에서 발견해버린 Warning: Prop id did not match. Server: "react-selec-2-live-region" Client: "react-select-3-live-region"

찾아보니 react-select 깃허브 레포지토리에서 같은 문제로 생성되었던 이슈 내용을 발견할 수 있었다. 관련 Issue#2629

Issue#2629 on May 20, 2018

solve

사실 위에서 추가한 관련 이슈 링크에서 연결된 글들을 읽어보면 해결책을 찾을 수 있는데, 여전히 해결책이 통하지 않는다는 이야기도 함께 보인다. 일단 위에서부터 읽어 내려오며 시도해 봤다.

처음엔 작성한 Input.Select 컴포넌트에 id, 그다음엔 instanceId와 inputId까지 추가해 봤지만 오류가 사라지지 않았다.

첫번째 시도: Input.Select에 id, instanceId, inputId 속성 추가

그리고 아래 이미지와 같이 다른 개발자가 관련 문제를 해결하고 PR 한 내용을 보게 되었다.

'https://github.com/buildo/bento-design-system/pull/859'에서 문제 해결을 위해 작성한 코드(File changed)

바뀐 코드를 보면 컴포넌트에서 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.

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: hydrateRoot lets you display React components inside a browser DOM node whose HTML content was previously generated by react-dom/server.

hydrateRoot lets you display React components inside a browser DOM node whose HTML content was previously generated by react-dom/server.
hydrateRootreact-dom/server에서 사전에 생성한 HTML 컨텐츠가 들어있는 브라우저 DOM 내부에 React 컴포넌트를 표시할 수 있도록 합니다.

react-select의 Select 컴포넌트는 클라이언트 컴포넌트로 사용해야 하기 때문에 이 컴포넌트를 사용하는 페이지에서 하이드레이션이 발생할 수밖에 없고 이 과정에서 id를 지정해 주지 않으면 위와 같은 오류가 발생하게 되는 것이다.

Thank You for Visiting My Blog, Have a Good Day 😸
© 2022 Developer 나연, Powered By Gatsby.