はじめに
今回は、ユーザーがタイトルを入力すると同時に、API を使って「タイトル候補」をリアルタイムで提示する UI を実装してみました。
狙っている UX は次のような流れになります。
1. ユーザーがタイピングを開始
2. バックエンド API を呼び出し:
isTitleLoading が true になり「候補取得中...」と表示
3. オートコンプリートの提示:
titleSuggestions にデータが入ると、datalist を通じて候補が表示される
1. input と datalist の紐付けは必須
datalist を機能させるには、input 側の list 属性と、datalist 側の id を完全に一致させる必要があります。
<input
id="title"
value={formData.title}
list="title-suggestions" // IDと一致させる
onChange={handleTitleChange}
placeholder="作品タイトルを入力..."
required
/>
<datalist id="title-suggestions">
{titleSuggestions.map((title) => (
<option key={title} value={title} />
))}
</datalist>
注意:
これを忘れると、バックエンドからデータが届いても UI 上に候補リストが表示されません。
2. APIからタイトル呼び出し
1. ユーザーがタイトルを入力する
2. useEffect が発火する
3. 入力が 400ms 止まると検索開始(デバウンス)
4. setTitleSuggestions(uniqueTitles) で候補を state に保存
5. datalist がその state を使って option を生成
useEffect(() => {
const title = formData.title.trim();
if (!title) {
setTitleSuggestions([]);
return;
}
const timeout = setTimeout(async () => {
const titlesData = await searchtitlesData(title);
setTitleSuggestions(titlesData);
}, 400);
return () => clearTimeout(timeout);
}, [formData.title]);
API の呼びすぎを防ぐための対策
有料の API を利用している場合、最適化を行わないと 1 文字打つたびに料金が発生し、すぐにレート制限(429 Error)にかかってしまいます。また入力のたびに API を叩くと、ネットワーク負荷が増大し、動作が重くなる原因になります。そのため、以下のような対策を行うことが定石となります。
Debounce(デバウンス)の実装:
ユーザーがタイピングを止めてから一定時間(例: 0.5秒)経過した後にのみ API を実行します。
// lodashのdebounceなどを使用する例
const debouncedFetch = useCallback(
debounce((value) => {
fetchTitleSuggestions(value);
}, 500),
[]
);
const handleTitleChange = (e) => {
const value = e.target.value;
setTitle(value);
// タイピングのたびに実行されるが、実際のAPI呼び出しは500ms後
debouncedFetch(value);
};
文字数制限の追加:
「1文字入力されただけで全件検索」のような無駄を防ぐため、3文字以上の場合のみ実行するガード節を入れます。
if (value.trim().length >= 3) {
debouncedFetch(value);
}
3. Next.js でのローディング演出
isTitleLoading フラグを利用して「取得中...」の状態を可視化します。これにより、ユーザーは「今、システムが考えているんだな」と認識でき、UX が向上します。
{isTitleLoading && (
<p className="mt-2 text-xs text-blue-500">
タイトル候補を取得中...
</p>
)}
まとめ
いかがだったでしょうか?
私が現在制作しているアプリで使用している API は課金制ではないため、現状では制限を強く意識する必要はありませんが、今回紹介した Debounce や 文字数制限 は、コスト削減だけでなく、サーバー負荷の軽減にも直結する必須技術です。
これらを活用して、スムーズでスマートな UX を追求していきましょう!