[React] useId()를 사용하다가 삽질한 기록

2025. 5. 25. 08:08·Development/React

React.useId()란?

React.useId()는 React 18에 도입된 훅으로, 컴포넌트 렌더링마다 고유한 ID 문자열을 생성해 주는 기능을 제공한다.

  • HTML의 id, htmlFor 속성 같이 접근성과 연관된 DOM 요소를 연결할 때 유용
  • SSR(Server Side Rendering) 시에도 클라이언트와 일관된 ID 보장

주로, HTML의 id, htmlFor 속성처럼 접근성과 관련된 DOM 요소를 연결할 때 사용되며, SSR(server Side Rendering) 환경에서 클라이언트와 서버 간 ID 일치(hydration-safe)를 보장한다.

또한 React 내부적으로 렌더 트리 순서를 기준으로 ID를 생성하기 때문에, 렌더링 간에 ID 충돌 없이 고유한 값을 갖는다.

하지만 리액트 내부에서 key값으로 사용은 권장하지 않는다. React에서의 key는 컴포넌트 재사용 및 리렌더링 최적화를 위한 용도로 설계되어 있기 때문이다.

 

React Key
- key prop을 위한 값
- 컴포넌트 재사용/리렌더링 최적화용

선을 그리는 작업에 useId()를 썼다가 발생한 문제

최근 SVG path에 선을 그리는 작업 중, marker를 위한 ID를 만들기 위해 useId()를 사용해 봤다.

이유는 단순했다. 계층형 데이터에서 고유한 아이디값이 중복되어 표시되는 경우가 있었기 때문. (그러지 말았어야 했는데)

데이터 자체는 중복 데이터가 아니지만, UI 단에서는 사용자 편의를 위해 같은 데이터를 여러 위치에 중복해서 렌더링 되는 구조였다.

(같은 아이디가, 여러 부모 아래에서 보일 수 있는 식)

사실 백엔드에서 수정해서 고유 값을 받았어야 했는데 개발이 딜레이 되면서 프런트에서 일단 해결하고자 했다. 

 

<marker id={markerId} />
<path markerEnd={`url(#${markerId})`} />

SVG에서 markerEnd는 <marker> 엘리먼트의 id를 참조하여 선 끝에 화살표 등 연결을 표현하는 방식인데, 이때 중요한 건 <path>와 <marker>의 ID가 정확히 일치하지 않으면 선이 그려지지 않는다.

그래서 고유한 아이디를 만들자는 생각에 useId()를 썼는데, 내가 기대한 방식과 실제 동작 방식은 달랐다.


문제가 발생한 이유

현재 개발하는 환경은 SSR을 사용하지 않는 CSR 기반 환경이고, 또한 선을 그리는 컴포넌트는 조건부 렌더링(토글)으로 인해 자주 언마운트되고 다시 마운트 되는 구조였다.

더 혼란스러웠던 건, 어떤 경우에는 선이 정상적으로 보이고, 어떤 경우에는 보이지 않았다는 점.

클릭하는 요소에 따라 어떤 컴포넌트는 언마운트되고, 어떤 컴포넌트는 그대로 유지되면서 useId값이 계속 변하고 있었던 것이었다.

전부 동작하지 않았으면 차라리 문제를 일찍 눈치챘을 텐데, 일부 케이스에서는 선이 정상적으로 보였기 때문에

문제의 원인을 useId()에서 찾게 되기까지 꽤 삽질을 하게 되었다.

 

원인은 useId()의 재생성 방식

useId()는 컴포넌트가 언마운트되었다가 마운트 될 경우 새로운 ID를 발급한다.

즉, 같은 요소를 보는 것 같아도 내부적으로는 매번 다른 ID를 가지고 있는 셈이다.

 

그래서 다음과 같은 문제가 생겼다.

<marker id="react-aria123-1" />
<path markerEnd="url(#react-aria123-2)" />
  • <marker id="react-aria123-1" />가 먼저 렌더 됨
  • 이후 <path markerEnd="url(#react-aria123-2)" />가 렌더 됨

→ ID가 서로 다르기 때문에 선이 표시되지 않는다.

 

useId()로 생성된 아이디: 로그를 보면, 클릭할 때마다 마운트 되어 새로운 아이디가 생성되는 걸 볼 수 있다.

로그를 찍어보니 클릭할 때마다 새로운 ID가 생성되는 걸 확인할 수 있었고,

React가 ID 생성은 보장하지만 “지속성”은 보장하지 않는다는 점을 알게 되었다.

  • 즉, 언마운트 → 재마운트 되면 ID는 다시 만들어지는 구조다.

 

결론적으로:

  • useId()는 SSR을 사용하는 환경이나
  • 초기 렌더에서만 필요한 고유 ID 생성에는 적합하다.
  • 하지만 렌더마다 일관된 ID가 필요한 작업에는 적절하지 않다.
  • 특히 SVG path처럼 ID 일치가 필수인 작업에서는
  • useId()보다는 고정된 key 값이나 백엔드에서 넘겨주는 식별자를 사용하는 것이 더 안정적이다.

 

늘 느끼지만 공식문서를 잘 보고 써야겠다...


참고

https://react.dev/reference/react/useId

 

useId – React

The library for web and native user interfaces

react.dev

 

'Development > React' 카테고리의 다른 글

[React] ReactQuery 순환 참조  (1) 2025.06.09
[React] React에서 key 중복으로 발생한 렌더링 이슈 (Reconciliation 사례)  (1) 2025.05.27
[TypeScript] 고급 타입 활용법: 조건부 타입, 제네릭 심화와 Exclude/Extract 활용  (0) 2025.04.01
[React] 상태 (State)  (0) 2024.02.28
[React] JSX 사용하기  (0) 2024.02.28
'Development/React' 카테고리의 다른 글
  • [React] ReactQuery 순환 참조
  • [React] React에서 key 중복으로 발생한 렌더링 이슈 (Reconciliation 사례)
  • [TypeScript] 고급 타입 활용법: 조건부 타입, 제네릭 심화와 Exclude/Extract 활용
  • [React] 상태 (State)
곽진돔
곽진돔
Developer
  • 곽진돔
    echo "곽박한 세상";
    곽진돔
  • 전체
    오늘
    어제
    • 분류 전체보기 (184)
      • Development (57)
        • Linux (13)
        • k8s (3)
        • Docker (5)
        • AWS (1)
        • PHP (35)
        • Python (21)
        • Java (1)
        • SpringBoot (4)
        • JavaScript (1)
        • React (8)
        • MySql (19)
        • MongoDB (1)
      • Daily (4)
      • Study (6)
        • TIL (1)
        • license (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 글쓰기
    • 설정
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    db
    Linux
    Java
    error
    리눅스
    윈도우
    MySQL
    nodejs
    chromedriver
    docker
    HTML
    크롤링
    date
    JavaScript
    정규표현식
    인코딩
    php
    리액트
    스프링부트
    CentOS
    SQL
    react
    Shell
    IP
    Selenium
    UTF8
    ssh
    CentOS7
    Python
    springboot
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
곽진돔
[React] useId()를 사용하다가 삽질한 기록
상단으로

티스토리툴바