useId
는 접근성 속성에 전달할 수 있는 고유 ID를 생성하기 위한 React 훅입니다.const id = useId()
참조
useId()
useId
는 컴포넌트의 최상위 수준에서 호출하여 고유한 ID를 생성합니다:import { useId } from 'react'; function PasswordField() { const passwordHintId = useId(); // ...
매개변수
useId
는 매개변수를 사용하지 않습니다.반환값
useId
는 특정 컴포넌트 내 특정 useId
와 관련된 고유 ID 문자열를 반환합니다.주의사항
useId
는 훅이므로 컴포넌트 최상단 또는 훅에서만 호출할 수 있습니다. 반복문이나 조건문 내에서 호출할 수 없습니다. 필요한 경우, 새로운 컴포넌트를 추출하고 컴포넌트 state로 이동하세요.
useId
를 배열에서 키를 생성하기 위해 사용하지 마세요. 키는 데이터에서 생성되어야 합니다.
사용법
Pitfall | 함정
useId
를 배열에서 키를 생성하기 위해 호출하지 마세요. 키는 데이터에서 생성되어야 합니다.접근성 속성에 대한 고유 ID 생성
컴포넌트 최상단에서
useId
를 호출하여 고유 ID값을 생성합니다.import { useId } from 'react'; function PasswordField() { const passwordHintId = useId(); // ...
생성된 ID를 다른 속성에 전달할 수 있습니다:
<> <input type="password" aria-describedby={passwordHintId} /> <p id={passwordHintId}> </>
유용한 경우를 알아보기 위해 예제를 살펴보겠습니다.
aria-describedby
와 같은 HTML 접근성 속성 은 두 태그가 서로 연관되어 있음을 알 수 있습니다. 예를 들어, 한 요소(input 등)에 대한 설명을 다른 요소(문단 등)가 대신하도록 지정할 수 있습니다.일반 HTML에서는 다음과 같이 작성합니다:
<> <input type="password" aria-describedby={passwordHintId} /> <p id={passwordHintId}> </>
그러나 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> </> ); }
이제
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 /> </> ); }
이 비디오를 시청하여 보조과학기술을 통한 사용자 경험의 차이를 확인하십시오.
Pitfall | 함정
서버 렌더링을 사용하면,
useId
와 클라이언트에서 동일한 컴포넌트 트리가 필요합니다. 서버와 클라이언트에서 렌더링한 트리가 정확히 일치하지 않으면 생성된 ID가 일치하지 않습니다.DEEP DIVE | 심층 탐구
증가 카운터보다 useId가 더 나은 이유는 무엇일까?
useId
가 nextId++
처럼 전역 변수를 증가시키는 것보다 무엇이 더 나은지 궁금할 수 있습니다.useId
의 주요 이점은 React가 서버 렌더링과 함께 작동하도록 보장한다는 것입니다. 서버 렌더링 중에 컴포넌트는 HTML 출력을 생성합니다. 이후 클라이언트에서 hydration이 붙여진 이벤트 핸들러를 생성된 HTML에 연결합니다. hydration이 작동하려면 클라이언트의 출력물이 서버 HTML과 일치해야 합니다.클라이언트 컴포넌트가 hydration 되는 순서가 서버 HTML이 생성된 순서와 일치하지 않을 수 있기 때문에, 증가 카운터로는 이를 보장하기가 매우 어렵습니다.
useId
를 호출하면 hydration이 작동하고, 서버와 클라이언트의 출력물이 서로 일치하는지 확인할 수 있습니다.React 내부에서
useId
는 호출한 컴포넌트의 “부모 경로”에서 생성됩니다. 그렇기 때문에 클라이언트와 서버 트리가 동일하면 렌더링 순서와 상관 없이 “부모 경로”가 일치하게 되므로, useId
역시 일치할 것입니다.여러 관련 요소에 대한 ID 생성
여러 관련 요소에 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> ); }
useId
를 통해 고유 ID가 필요한 모든 단일 요소를 호출하지 않아도 됩니다 .생성된 모든 ID에 공유 접두사 지정하기
단일 페이지에서 여러 개의 독립적인 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 />); // Generated identifier: :my-first-app-생성된아이디 const root2 = createRoot(document.getElementById('root2'), { identifierPrefix: 'my-second-app-' }); root2.render(<App />); // Generated identifier: :my-second-app-생성된아이디