useId, erişilebilirlik özniteliklerine iletmek üzere benzersiz kimlikler üreten React Hook’udur.

const id = useId()

Referans

useId()

Benzersiz bir kimlik oluşturmak için useId’yi bileşeninizin en üst kapsamında çağırın:

import { useId } from 'react';

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

Daha fazla örnek için aşağıya bakın.

Parametreler

Herhangi bir parametre almaz.

Dönüş değeri

Çağrıldığı bileşene özel olarak her bir useId çağrısı için karakter dizisi (string) tipinde benzersiz kimlik döner.

Dikkat edilmesi gerekenler

  • useId bir Hook olduğundan, yalnızca bileşeninizin en üst kapsamında ya da kendi Hook’larınızda çağırabilirsiniz. Döngülerin ve koşulların içinde çağıramazsınız. Eğer çağırmak zorunda kaldıysanız yeni bir bileşene çıkarın ve state’i ona taşıyın.

  • Liste elemanlarına anahtar üretmek için kullanılmamalıdır. Anahtarlar elinizdeki veriden üretilmelidir.


Kullanım

Tuzak

Anahtar üretmek için useId kullanmayın. Anahtarlar elinizdeki veriden üretilmelidir.

Erişilebilirlik öznitelikleri için benzersiz kimlikler üretmek

Benzersiz kimlikler üretmek için bileşeninizin en üst kapsamında useId’yi çağırın:

import { useId } from 'react';

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

Daha sonra oluşturulan kimliği farklı özniteliklere iletebilirsiniz:

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

Bunun ne zaman faydalı olabileceğini görmek için bir örnek üzerinden ilerleyelim.

aria-describedby gibi HTML erişilebilirlik öznitelikleri, iki etiketin birbirine bağlı olduğunu belirtmenizi sağlar. Örneğin, bir elementin (mesela <input>) başka bir element (mesela <p>) tarafından tanımlandığını belirtebilirsiniz.

Saf HTML’de bunu şu şekilde yazarsınız:

<label>
Şifre:
<input
type="password"
aria-describedby="password-hint"
/>
</label>
<p id="password-hint">
Şifre en az 18 karakter içermelidir
</p>

Ancak, doğrudan koda yazılan kimlikler React’ta iyi bir pratik değildir. Bir bileşen sayfada birden fazla kez render edilebilir—ancak kimlikler benzersiz olmalıdır! Bunun yerine useId ile benzersiz bir kimlik oluşturun:

import { useId } from 'react';

function PasswordField() {
const passwordHintId = useId();
return (
<>
<label>
Şifre:
<input
type="password"
aria-describedby={passwordHintId}
/>
</label>
<p id={passwordHintId}>
Şifre en az 18 karakter içermelidir
</p>
</>
);
}

Artık PasswordField ekranda birden fazla kez görünse bile üretilen kimlikler çakışmaz.

import { useId } from 'react';

function PasswordField() {
  const passwordHintId = useId();
  return (
    <>
      <label>
        Şifre:
        <input
          type="password"
          aria-describedby={passwordHintId}
        />
      </label>
      <p id={passwordHintId}>
        Şifre en az 18 karakter içermelidir
      </p>
    </>
  );
}

export default function App() {
  return (
    <>
      <h2>Şifreni seç</h2>
      <PasswordField />
      <h2>Şifreni doğrula</h2>
      <PasswordField />
    </>
  );
}

Yardımcı teknolojiler ile edinilen kullanıcı deneyiminde yarattığı farkı görmek için bu videoyu izleyin.

Tuzak

Sunucu taraflı render ile birlikte kullanılan useId, sunucu ve istemci tarafında özdeş bileşen ağacına gereksinim duyar. Sunucu ve istemcide render edilen ağaçlar birebir eşleşmezse, oluşan kimlikler de eşleşmeyecektir.

Derinlemesine İnceleme

Neden useId kullanmak artan bir sayaca nazaran daha iyidir?

useId’nin nextId++ gibi global bir değişkeni arttırmaktan neden daha iyi olduğunu merak ediyor olabilirsiniz.

Temel avantajı, React’ın sunucu taraflı render ile çalışacağını garanti etmesidir. Bileşenleriniz sunucu taraflı render ensasında HTML çıktısı üretir. Ardından istemcide, üretilen HTML’e hidratlama (hydration) sırasında olay yöneticileri eklenir. Hidratlamanın çalışması için, istemci çıktısının sunucu HTML’iyle eşleşmesi gerekir.

Artan sayaç kullanarak bunu garanti etmek çok zordur. İstemci bileşenlerinin hidratlanma sırası ile sunucu HTML’inin tarayıcıya gönderilme sırası eşleşmeyebilir. useId’yi çağırmak; hidratlamanın çalışacağından, sunucu ve istemci arasındaki çıktının özdeş olacağından emin olmanızı sağlar.

React’ta useId’nin değeri, çağrıldığı bileşenin ağaç içindeki hiyerarşik yolundan (parent path) üretilir. Dolayısıyla sunucu ve istemci ağaçları aynıysa, ürettikleri değerler render sırasına bakılmaksızın eşleşecektir.


Bir takım ilişkili elemente kimlik vermeniz gerekiyorsa, useId’yi çağırarak ürettiğiniz kimliği sonekler ile özelleştirebilirsiniz:

import { useId } from 'react';

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

Bu kullanım, benzersiz kimliğe ihtiyaç duyan her bir element için useId’yi çağırmaktan kaçınmanızı sağlar.


Üretilen tüm kimlikler için önek belirlemek

Tek bir sayfada birden fazla bağımsız React uygulaması render ederseniz, createRoot veya hydrateRoot metodlarına iletebileceğiniz identifierPrefix parametresini kullanın. Bu sayede useId ile oluşturulan her bir kimlik benzersiz bir önek ile başlayacağından, iki farklı uygulama tarafından oluşturulan kimlikler asla çakışmaz.

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.