useId adalah React Hook untuk menghasilkan ID unik yang dapat diteruskan ke atribut aksesibilitas.

const id = useId()

Referensi

useId()

Panggil useId di tingkat teratas komponen Anda untuk menghasilkan ID unik:

import { useId } from 'react';

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

Lihat lebih banyak contoh di bawah ini.

Parameter

useId tidak mengambil parameter apapun.

Kembalian

useId mengembalikan string ID unik yang terkait dengan panggilan useId tertentu dalam komponen khusus ini.

Caveats

  • useId adalah sebuah Hook, jadi Anda hanya dapat memanggilnya di tingkat teratas komponen Anda atau Hook Anda sendiri. Anda tidak dapat memanggilnya di dalam perulangan (loops) atau kondisi (conditions). Jika Anda membutuhkannya, ekstrak komponen baru dan pindahkan state ke dalamnya.

  • useId tidak boleh digunakan untuk menghasilkan key dalam daftar. Key harus dihasilkan dari data Anda.


Pengunaan

Sandungan

Jangan panggil useId untuk menghasilkan key dalam daftar. Key harus dihasilkan dari data Anda

Menghasilkan ID unik untuk atribut aksesibilitas

Panggil useId di tingkat atas komponen Anda untuk menghasilkan ID unik:

import { useId } from 'react';

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

Anda kemudian dapat meneruskan ID yang dihasilkan ke atribut yang berbeda:

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

Mari telusuri contoh untuk melihat kapan ini berguna.

Atribut aksesibilitas HTML seperti aria-describedby membiarkan Anda menentukan bahwa dua tag terkait satu sama lain. Misalnya, Anda dapat menentukan bahwa suatu elemen (seperti sebuah masukan (input)) dijelaskan oleh elemen lain (seperti sebuah paragraf (p)).

Dalam HTML biasa, Anda akan menulisnya seperti ini:

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

Namun, menuliskan ID secara langsung di dalam kode (hardcoding) seperti ini bukanlah praktik yang baik di React. Sebuah komponen dapat di-render lebih dari sekali pada halaman—namun ID harus unik! Alih-alih melakukan pemaksaan ID, buat ID unik dengan useId:

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>
</>
);
}

Sekarang, meskipun PasswordField muncul beberapa kali di layar, ID yang dihasilkan tidak akan berbenturan.

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 />
    </>
  );
}

Tonton video ini untuk melihat perbedaan pengalaman pengguna dengan teknologi bantu.

Sandungan

Dengan server rendering, useId membutuhkan pohon komponen yang identik di server dan klien. Jika pohon yang Anda render di server dan klien tidak sama persis, ID yang dihasilkan tidak akan cocok.

Pendalaman

Mengapa useId lebih baik daripada penghitung kenaikan?

Anda mungkin bertanya-tanya mengapa useId lebih baik daripada menambahkan variabel global seperti nextId++.

Manfaat utama useId adalah React memastikan bahwa ia bekerja dengan server rendering. Selama server rendering, komponen Anda menghasilkan keluaran HTML. Kemudian, pada klien, hidrasi melampirkan event handler Anda ke HTML yang dihasilkan. Agar hidrasi berfungsi, output klien harus cocok dengan HTML dari server.

Hal ini sangat sulit untuk dijamin dengan penghitung kenaikan karena urutan di mana komponen klien terhidrasi mungkin tidak sesuai dengan urutan di mana HTML dari server dipancarkan. Dengan memanggil useId, Anda memastikan bahwa hidrasi akan berfungsi, dan hasilnya akan cocok antara server dan klien.

Di dalam React, useId dihasilkan dari “jalur induk” dari komponen pemanggil. Inilah sebabnya, jika pohon di klien dan server sama, “jalur induk” akan cocok terlepas dari urutan rendering.


Jika Anda perlu memberikan ID ke beberapa elemen terkait, Anda dapat memanggil useId untuk menghasilkan awalan bersama untuk mereka:

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>
  );
}

Ini memungkinkan Anda menghindari pemanggilan useId untuk setiap elemen yang membutuhkan ID unik.


Menentukan awalan bersama untuk semua ID yang dihasilkan

Jika Anda me-render beberapa aplikasi React independen pada satu halaman, berikan identifierPrefix sebagai opsi untuk panggilan createRoot atau hydrateRoot Anda. Hal ini memastikan bahwa ID yang dihasilkan oleh dua aplikasi berbeda tidak pernah berbenturan karena setiap pengenal yang dibuat dengan useId akan dimulai dengan awalan berbeda yang telah Anda tentukan.

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.