useId is a React Hook for generating unique IDs that can be passed to accessibility attributes. useId는 접근성 속성에 전달할 수 있는 고유 ID를 생성하기 위한 React 훅입니다.

const id = useId()

Reference참조

useId()

Call useId at the top level of your component to generate a unique ID: useId는 컴포넌트의 최상위 수준에서 호출하여 고유한 ID를 생성합니다:

import { useId } from 'react';

function PasswordField() {
const passwordHintId = useId();
// ...

See more examples below. 아래에서 더 많은 예시를 확인하세요.

Parameters매개변수

useId does not take any parameters. useId는 매개변수를 사용하지 않습니다.

Returns반환값

useId returns a unique ID string associated with this particular useId call in this particular component. useId는 특정 컴포넌트 내 특정 useId 와 관련된 고유 ID 문자열를 반환합니다.

Caveats주의사항

  • useId is a Hook, so you can only call it at the top level of your component or your own Hooks. You can’t call it inside loops or conditions. If you need that, extract a new component and move the state into it. useId는 훅이므로 컴포넌트 최상단 또는 훅에서만 호출할 수 있습니다. 반복문이나 조건문 내에서 호출할 수 없습니다. 필요한 경우, 새로운 컴포넌트를 추출하고 컴포넌트 state로 이동하세요.

  • useId should not be used to generate keys in a list. Keys should be generated from your data. useId를 목록에서 키를 생성하기 위해 사용하지 마세요. 키는 데이터에서 생성되어야 합니다.


Usage사용법

Pitfall | 함정

Do not call useId to generate keys in a list. Keys should be generated from your data. useId를 목록에서 키를 생성하기 위해 호출하지 마세요. 키는 데이터에서 생성되어야 합니다.

Generating unique IDs for accessibility attributes 접근성 속성에 대한 고유 ID 생성

Call useId at the top level of your component to generate a unique ID: 컴포넌트 최상단에서 useId를 호출하여 고유 ID값을 생성합니다.

import { useId } from 'react';

function PasswordField() {
const passwordHintId = useId();
// ...

You can then pass the generated ID to different attributes: 생성된 ID를 다른 속성에 전달할 수 있습니다:

<>
<input type="password" aria-describedby={passwordHintId} />
<p id={passwordHintId}>
</>

Let’s walk through an example to see when this is useful. 유용한 경우를 알아보기 위해 예제를 살펴보겠습니다.

HTML accessibility attributes like aria-describedby let you specify that two tags are related to each other. For example, you can specify that an element (like an input) is described by another element (like a paragraph). aria-describedby와 같은 HTML 접근성 속성 은 두 태그가 서로 연관되어 있음을 알 수 있습니다. 예를 들어, 한 요소(input 등)에 대한 설명을 다른 요소(문단 등)가 대신하도록 지정할 수 있습니다.

In regular HTML, you would write it like this: 일반 HTML에서는 다음과 같이 작성합니다:

<label>
Password:
<input
type="password"
aria-describedby="password-hint"
/>
</label>
<p id="password-hint">
The password should contain at least 18 characters
</p>

However, hardcoding IDs like this is not a good practice in React. A component may be rendered more than once on the page—but IDs have to be unique! Instead of hardcoding an ID, generate a unique ID with useId: 그러나 ID를 하드코딩하는 것은 React에서 좋은 방법은 아닙니다. 컴포넌트는 페이지에서 두 번 이상 렌더링될 수 있지만 ID는 고유해야합니다! ID를 하드코딩하는 대신, useId로 고유한 ID를 생성하세요:

import { useId } from 'react';

function PasswordField() {
const passwordHintId = useId();
return (
<>
<label>
Password:
<input
type="password"
aria-describedby={passwordHintId}
/>
</label>
<p id={passwordHintId}>
The password should contain at least 18 characters
</p>
</>
);
}

Now, even if PasswordField appears multiple times on the screen, the generated IDs won’t clash. 이제 PasswordField가 화면에 여러번 나타나도 생성된 ID가 충돌하지 않습니다.

import { useId } from 'react';

function PasswordField() {
  const passwordHintId = useId();
  return (
    <>
      <label>
        Password:
        <input
          type="password"
          aria-describedby={passwordHintId}
        />
      </label>
      <p id={passwordHintId}>
        The password should contain at least 18 characters
      </p>
    </>
  );
}

export default function App() {
  return (
    <>
      <h2>Choose password</h2>
      <PasswordField />
      <h2>Confirm password</h2>
      <PasswordField />
    </>
  );
}

Watch this video to see the difference in the user experience with assistive technologies. 이 비디오를 시청하여 보조과학기술을 통한 사용자 경험의 차이를 확인하십시오.

Pitfall | 함정

With server rendering, useId requires an identical component tree on the server and the client. If the trees you render on the server and the client don’t match exactly, the generated IDs won’t match. 서버 렌더링을 사용하면, useId와 클라이언트에서 동일한 컴포넌트 트리가 필요합니다. 서버와 클라이언트에서 렌더링한 트리가 정확히 일치하지 않으면 생성된 ID가 일치하지 않습니다.

Deep Dive | 심층 탐구

Why is useId better than an incrementing counter? 중복 카운터보다 useId가 더 나은 이유는 무엇일까?

You might be wondering why useId is better than incrementing a global variable like nextId++. useIdnextId++처럼 전역 변수를 증가시키는 것보다 무엇이 더 나은지 궁금할 수 있습니다.

The primary benefit of useId is that React ensures that it works with server rendering. During server rendering, your components generate HTML output. Later, on the client, hydration attaches your event handlers to the generated HTML. For hydration to work, the client output must match the server HTML. useId 의 주요 이점은 React가 서버 렌더링과 함께 작동하도록 보장한다는 것입니다. 서버 렌더링 중에 컴포넌트는 HTML 출력을 생성합니다. 이후 클라이언트에서 hydration이 붙여진 이벤트 핸들러를 생성된 HTML에 연결합니다. hydration이 작동하려면 클라이언트의 출력물이 서버 HTML과 일치해야 합니다.

This is very difficult to guarantee with an incrementing counter because the order in which the client components are hydrated may not match the order in which the server HTML was emitted. By calling useId, you ensure that hydration will work, and the output will match between the server and the client. 클라이언트 컴포넌트가 hydration 되는 순서가 서버 HTML이 생성된 순서와 일치하지 않을 수 있기 때문에, 증가 카운터로는 이를 보장하기가 매우 어렵습니다. useId를 호출하면 hydration이 작동하고, 서버와 클라이언트의 출력물이 서로 일치하는지 확인할 수 있습니다.

Inside React, useId is generated from the “parent path” of the calling component. This is why, if the client and the server tree are the same, the “parent path” will match up regardless of rendering order. React 내부에서 useId는 호출한 컴포넌트의 “부모 경로”에서 생성됩니다. 그렇기 때문에 클라이언트와 서버 트리가 동일하면 렌더링 순서와 상관 없이 “부모 경로”가 일치하게 되므로, useId 역시 일치할 것입니다.


If you need to give IDs to multiple related elements, you can call useId to generate a shared prefix for them: 여러 관련 요소에 ID를 제공해야 하는 경우, useId를 호출하여 해당 요소들이 공유하는 접두사를 생성할 수 있습니다.

import { useId } from 'react';

export default function Form() {
  const id = useId();
  return (
    <form>
      <label htmlFor={id + '-firstName'}>First Name:</label>
      <input id={id + '-firstName'} type="text" />
      <hr />
      <label htmlFor={id + '-lastName'}>Last Name:</label>
      <input id={id + '-lastName'} type="text" />
    </form>
  );
}

This lets you avoid calling useId for every single element that needs a unique ID. useId를 통해 고유 ID가 필요한 모든 단일 요소를 호출하지 않아도 됩니다 .


Specifying a shared prefix for all generated IDs 생성된 모든 ID에 공유 접두사 지정하기

If you render multiple independent React applications on a single page, pass identifierPrefix as an option to your createRoot or hydrateRoot calls. This ensures that the IDs generated by the two different apps never clash because every identifier generated with useId will start with the distinct prefix you’ve specified. 단일 페이지에서 여러 개의 독립적인 React 애플리케이션을 렌더링하는 경우, createRoot 또는 hydrateRoot를 호출하여 identifierPrefix에 옵션으로 전달하세요. 이렇게 하면 생성된 모든 식별자가 지정한 고유한 접두사로 시작하기 때문에 서로 다른 두 앱에서 생성된 ID가 충돌하지 않습니다.

import { createRoot } from 'react-dom/client';
import App from './App.js';
import './styles.css';

const root1 = createRoot(document.getElementById('root1'), {
  identifierPrefix: 'my-first-app-'
});
root1.render(<App />);

const root2 = createRoot(document.getElementById('root2'), {
  identifierPrefix: 'my-second-app-'
});
root2.render(<App />);


Using the same ID prefix on the client and the server

If you render multiple independent React apps on the same page, and some of these apps are server-rendered, make sure that the identifierPrefix you pass to the hydrateRoot call on the client side is the same as the identifierPrefix you pass to the server APIs such as renderToPipeableStream.

// Server
import { renderToPipeableStream } from 'react-dom/server';

const { pipe } = renderToPipeableStream(
<App />,
{ identifierPrefix: 'react-app1' }
);
// Client
import { hydrateRoot } from 'react-dom/client';

const domNode = document.getElementById('root');
const root = hydrateRoot(
domNode,
reactNode,
{ identifierPrefix: 'react-app1' }
);

You do not need to pass identifierPrefix if you only have one React app on the page.