Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Coding Challenge Practice - Question 15

2025年09月25日に「Dev.to」が公開したITニュース「Coding Challenge Practice - Question 15」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Reactで電話番号入力UIを実装する課題。数字のみ受け付け、(XXX)XXX-XXXXに自動整形し、10桁に制限する。useStateや正規表現、文字列操作を活用した具体的なコード例で、ユーザーフレンドリーな入力フォーム作成の基本を解説。

出典: Coding Challenge Practice - Question 15 | Dev.to公開日:

ITニュース解説

この記事は、Webアプリケーション開発で広く使われる「React(リアクト)」という技術を使って、電話番号を入力するための特別な部品、つまり「コンポーネント」をどのように作るかを解説している。このコンポーネントは、ユーザーが電話番号をより簡単かつ正確に入力できるように、いくつかの便利な機能が組み込まれている。

まず、この電話番号入力コンポーネントには、大きく三つの主要な要件がある。一つ目は、入力される文字が必ず数字だけであること。ユーザーが誤って文字や記号を入力しても、システムが自動的にそれらを取り除き、数字だけを残すようにする。二つ目は、入力された数字が自動的に「(123)456-7890」のような、一般的な電話番号の形式に整形されること。具体的には、4桁目の数字が入力されたときに最初の3桁が括弧で囲まれ、7桁目の数字が入力される直前、つまり6桁目の後にハイフンが自動的に挿入される。三つ目は、電話番号として標準的な10桁を超える数字は入力できないように制限することだ。これらの機能があることで、ユーザーは間違いなく、スムーズに電話番号を入力できるようになる。

では、具体的なコードの内容を見ながら、これらの要件がどのように実現されているかを段階的に見ていこう。Reactを使った開発では、画面上の要素を「コンポーネント」という独立した小さな部品に分けて作成するのが一般的だ。今回の「PhoneNumberInput」も、そのように作られた一つのコンポーネントである。

このコンポーネントの内部では、まず「const [value, setValue] = useState("")」というコードが登場する。これは、Reactでコンポーネントが持つ「状態」を管理するための重要な機能である「useState(ユースステート)」を使用している部分だ。ここで「value」は現在入力されている電話番号の文字列を、「setValue」はその「value」を更新するための関数を指す。「useState("")」の "" は、コンポーネントが最初に画面に表示されるとき、入力フィールドが空の状態から始まることを示している。この「value」が、入力フィールドに表示される内容と常に同期することになる。

次に、「handleChange」という関数が定義されている。この関数は、ユーザーが入力フィールドに何か文字を入力するたびに自動的に呼び出される役割を持つ。HTMLの<input>タグには「onChange」という属性があり、この属性にhandleChange関数を設定することで、入力内容が変更されるたびにこの関数が実行される仕組みになっている。

handleChange関数の中の最初の重要な処理は「let digits = e.target.value.replace(/\D/g, "")」という行だ。ここで「e.target.value」は、ユーザーが入力した現在の文字列全体を指している。この文字列に対して「.replace(/\D/g, "")」という処理が適用される。これは「正規表現(せいきひょうげん)」と呼ばれる、文字列の中から特定のパターンを検索したり置き換えたりするための強力な機能を利用したものだ。「\D」は「数字以外のすべての文字」という意味で、「g」は「文字列全体で合致するものをすべて」という意味を持つ。つまり、このコードは「入力された文字列の中から、数字以外のすべての文字を見つけ出し、それらを空の文字列("")に置き換える(削除する)」という指示を出している。この結果、「digits」という変数には、ユーザーが入力した文字の中から純粋な数字だけが抽出されて格納される。これで「数字のみを受け入れる」という最初の要件が満たされたことになる。

次のステップは、入力された数字の桁数を制限する処理だ。「if (digits.length > 10) { digits = digits.slice(0, 10); }」というコードがその役割を担う。「digits.length」は、抽出された数字の桁数を教えてくれる。もしこの桁数が10より大きくなったら、つまり11桁以上になったら、digits.slice(0, 10)という処理が実行される。「.slice(0, 10)」は、文字列の0番目の位置から数えて10文字目まで(つまり最初の10文字)を切り出すというメソッドだ。これにより、もしユーザーが11桁以上の数字を入力しても、最初の10桁だけが残り、それ以降の数字は自動的に切り捨てられる。これで「最大10桁まで」という要件が満たされる。

そして、このコンポーネントの最も特徴的な機能である、電話番号の自動整形処理が続く。「let formatted = digits;」で、まず整形前の数字だけの文字列をformattedという新しい変数にコピーする。その後の「if」文と「else if」文を使って、数字の桁数に応じて異なる整形ルールを適用している。

一つ目の整形ルールは「if (digits.length > 3 && digits.length <= 6)」の部分だ。これは、数字の桁数が4桁から6桁までの場合に適用される。例えば「123456」と入力された場合を考えてみよう。この条件に合致すると、「formatted = (${digits.slice(0,3)})${digits.slice(3)}」という処理が実行される。「digits.slice(0,3)」は最初の3桁(例: "123")を取り出し、「digits.slice(3)」は4桁目以降の残りの部分(例: "456")を取り出す。これらを「(」と「)」で囲んで結合することで、「(123)456」のような形式に整形される。ここで使われている「バッククォート」(`` ``)で囲まれた特別な文字列の書き方は「テンプレートリテラル」と呼ばれ、文字列の中に変数の値を直接埋め込む際に非常に便利な記法だ。

二つ目の整形ルールは「else if (digits.length > 6)」の部分だ。これは、数字の桁数が7桁以上になった場合に適用される。例えば「1234567890」と入力された場合を考えてみよう。この条件に合致すると、「formatted = (${digits.slice(0,3)})${digits.slice(3,6)}-${digits.slice(6)}」という処理が実行される。「digits.slice(0,3)」で最初の3桁(例: "123")、「digits.slice(3,6)」で4桁目から6桁目までの3桁(例: "456")、「digits.slice(6)」で7桁目以降の残りの桁(例: "7890")をそれぞれ取り出す。これらを組み合わせて「(123)456-7890`」のような形式に整形される。これにより、ユーザーが数字を入力するだけで、自動的に適切な電話番号の書式に整えられる。

これらの整形処理がすべて終わると、最後に「setValue(formatted)」が実行される。これは、整形された文字列(formatted)を、コンポーネントの状態変数である「value」にセットするという意味だ。このsetValue関数が呼び出されると、Reactはコンポーネントの表示を自動的に更新し、ユーザーの画面上の入力フィールドには、整形された電話番号が表示されることになる。

最終的なコンポーネントの見た目と動作は、return <input value={value} onChange={handleChange} data-testid="phone-number-input"/> の部分によって決まる。ここで重要なのは、<input>タグの「value={value}」という記述だ。これは、入力フィールドの現在の表示内容が、useStateで管理しているvalue変数と常に同期していることを意味する。そして「onChange={handleChange}」により、入力内容が変更されるたびに先ほどのhandleChange関数が呼び出され、入力値の処理と再整形が行われるという、一連の完璧な流れが完成する。

このようにして、「PhoneNumberInput」コンポーネントは、ユーザーが数字を入力するだけで、数字以外の文字を自動的に除外し、最大桁数を制限し、そして見やすい形式に自動整形するという、非常に使い勝手の良い機能を提供している。システムエンジニアにとって、このようなユーザーの使いやすさを考慮した機能の実装は、アプリケーション開発における重要な側面の一つであり、この記事はその具体的な実現方法を、Reactの基本的な仕組みと組み合わせて示している。

関連コンテンツ