useId
useId
は、アクセシビリティ属性に渡すことができる一意の ID を生成するための React フックです。
const id = useId()
リファレンス
useId()
コンポーネントのトップレベルで useId
を呼び出して、一意の ID を生成します。
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
// ...
パラメータ
useId
はパラメータを受け取りません。
返す
useId
は、特定のコンポーネント内で、この useId
の呼び出しに関連付けられた一意の ID 文字列を返します。
注意事項
-
useId
はフックであるため、コンポーネントのトップレベル または独自のフック内でのみ呼び出すことができます。ループまたは条件分岐内で呼び出すことはできません。もし必要な場合は、新しいコンポーネントを作成し、状態を移動させる必要があります。 -
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 アクセシビリティ属性を使用すると、2 つのタグが相互に関連していることを指定することができます。例えば、入力フィールドのような要素が、段落などの別の要素で説明されていることを指定することができます。
通常の HTML では、次のように記述します。
<label>
Password:
<input
type="password"
aria-describedby="password-hint"
/>
</label>
<p id="password-hint">
The password should contain at least 18 characters
</p>
ただし、このように 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 /> </> ); }
このビデオを見て支援技術による、ユーザ体験の違いを確認してみてください。
さらに深く知る
なぜ useId
が nextId++
のようなグローバル変数を増分するよりもなぜ良いのか、疑問に思われるかもしれません。
useId
の主な利点は、React が、サーバーレンダリング で、確実に機能することを保証しているためです。サーバーのレンダー中に、コンポーネントは HTML の出力を生成します。その後クライアント上で、生成された HTML に、ハイドレーション によって、イベント ハンドラがアタッチされます。ハイドレーションが機能するには、クライアントの出力がサーバーの HTML と一致する必要があります。
クライアントコンポーネントがハイドレートされる順序は、サーバー HTML が出力された順序と一致しない可能性があるため、これをインクリメントカウンタで保証することは非常に困難です。useId
を呼び出すことで、ハイドレーションが機能し、サーバーとクライアントの間で出力が一致することが保証されます。
React 内部では、呼び出し元コンポーネントの「親パス」から 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> ); }
これにより、一意の ID を必要とするすべての要素に対して useId
を呼び出す必要がなくなります。
生成されたすべての ID に共有プレフィックスを指定する
複数の独立した React アプリケーションを 1 つのページにレンダーする場合は、オプションとして identifierPrefix
を createRoot
または hydrateRoot
に渡します。これにより、useId
で生成されたすべての識別子が指定した個別のプレフィックスで始まるため、2 つの異なるアプリによって生成された 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 />);