본문 바로가기

리액트

[React] useId | 고유한 id 값을 생성해주는 리액트 훅

반응형

useId()

useId() 훅을 사용하면 컴포넌트가 렌더링될 때 마다 고유한 id 를 생성하여 반환해준다. 따라서, 이를 활용한다면, 같은 컴포넌트를 동일한 부모 컴포넌트에서 재사용하는 경우 서로 id 값이 같아서 충돌이 날 수 있는 문제를 사전에 예방할 수 있다.

 

예를 들어 유저의 이메일을 입력 받은 동일한 컴포넌트를 하나의 부모 컴포넌트에서 여러 번 재사용하는 경우를 가정해보자.

// 이메일을 입력받는 자식 컴포넌트
import { useState } from 'react';

function EmailInput({ onChange }) {
  const [email, setEmail] = useState('');

  const handleInputChange = (e) => {
    const { value } = e.target;
    setEmail(value);
    onChange(value); // 부모 컴포넌트에 이메일 값 전달
  };

  return (
    <div>
      <label htmlFor="email">이메일:</label>
      <input
        type="email"
        id="email"
        name="email"
        value={email}
        onChange={handleInputChange}
        placeholder="이메일을 입력하세요"
      />
    </div>
  );
}

export default EmailInput;

 

 

이 경우 부모 컴포넌트에서 동일한 id 를 사용하여 컴포넌트를 렌더링하게 되면 예기치 못한 id 충돌 문제가 발생할 수 있다. 즉, 서로 동일한 id 를 가지고 있기 때문에, 만일 두 번째 이메일 Input 의 라벨을 클릭하더라도 첫 번째 input 에 포커스가 생성되는 문제가 있을 수 있다.

import { useState } from 'react';
import EmailInput from './EmailInput';

function App() {
  const [userEmail1, setUserEmail1] = useState('');
  const [userEmail2, setUserEmail2] = useState('');

  const handleEmailChange1 = (email) => {
    setUserEmail1(email);
  };

  const handleEmailChange2 = (email) => {
    setUserEmail2(email);
  };

  return (
    <section>
      <h1> 테스트 입력 페이지 </h1>
      <div>
        <h2>메인 이메일</h2>
        <EmailInput onChange={handleEmailChange1} />
        <p>현재 입력된 이메일: {userEmail1}</p>
      </div>
      <div>
        <h2>서브 이메일</h2>
        <EmailInput onChange={handleEmailChange2} />
        <p>현재 입력된 이메일: {userEmail2}</p>
      </div>
    </section>
  );
}

export default App;

 

 

이러한 문제를 해결하기 위해서는 각 id 마다 고유한 값을 부여해야 하는데, 이를 위해서 아래와 같이 props 로 전달할 수도 있다. 

 

<EmailInput onChange={handleEmailChange1} id="main"/>
<EmailInput onChange={handleEmailChange2} id="sub" />

 

하지만, 리액트에서는 이러한 하드 코딩된 값을 사용하는 것을 권장하지 않고 있으며, 이를 개선하기 위한 훅으로 이 포스트의 주제인 userId() 훅을 v18 이후에 출시하였다.

 

useId() 훅을 사용한 고유 id 생성하기

우선, useId() 훅으로 생성된 id 값은 컴포넌트를 렌더링할 때 마다 새롭게 생성된다. 즉, 이 말은 동일한 컴포넌트라도 렌더링 되는 시점에 서로 다른 고유한 id 값을 생성해 줄 수 있다는 말이다. 따라서 이를 활용하여 다음과 같이 로직을 작성해보자

 

 

아래와 같이 작성하면, useId() 훅을 통해서 생성된 값이 id 변수에 할당되는데, 이 id 는 재사용된 컴포넌트 마다 다른 값을 생성하기 때문에, 같은 컴포넌트 끼리 id 가 충돌하는 문제를 해결할 수 있게 된다.

 

참고로, useId  는 리액트 훅이므로 컴포넌트 최상단에서 import  하고 컴포넌트 함수 상단에서 호출해야 한다.
import React from 'react';
import {useId} from 'react'; // useId 훅을 가져옴

function EmailInput({ onChange }) {
  const id = useId(); // 고유한 ID 생성

  const handleInputChange = (e) => {
    const { value } = e.target;
    onChange(value);
  };

  return (
    <div>
      <label htmlFor={id + 'email'}>이메일:</label>
      <input
        type="email"
        id={id + 'email'}
        name="email"
        onChange={handleInputChange}
        placeholder="이메일을 입력하세요"
      />
    </div>
  );
}

export default EmailInput;

 

 

추가적인 내용은 공식문서로

개인적으로 공식문서는 꼭 읽어보기를 권장한다. 특히, useId 를 사용하는 경우 얻을 수 있는 이점과 id++ 가 같은 증분이 되는 방식이 왜 리액트에서는 권장되지 않는 방식인지에 대한 내용도 소개되어 있다. 이를 기반으로 생각해본다면, 우리가 배열을 map 고차함수를 사용하여 렌더링할 때 key 에 index 를 바인딩하는 것을 권장하지 않는지에 대해서도 깊이 생각해 볼 수 있다고 본다.

 

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

 

useId – React

The library for web and native user interfaces

react.dev

 

반응형