Controlledのメリット
ReactではControlled Componentといって、デフォルトで<input>
などにデータは保存されず、onChange
イベントでデータを拾って回収する必要があります。
ただ、必ずしもこれは入力フォームのデータをそのまま保存する必要がない、ということでもあります。たとえば、内部で扱うデータは摂氏だけど、onChange
で華氏→摂氏に変換、value
で逆変換を行えば、データ構造に変化なくフォームだけ華氏に切り替えられます。
不可逆変換の、UX上の問題点
そのように、可逆な変換を行う分にはユーザーが気づく機会もなく、便利なだけなのですが、不可逆な変換を入れるととたんにややこしくなります。
たとえば、onChange
で数字をコンマ区切りにするような処理を入れた場合、「12,345」を入力するつもりであっても、「1234」まで入力したところで「1,234」となってしまい、なかなか気持ち悪いものとなります。
さらに、onChange
で特定の文字だけ削るような処理を入れると、その文字を入力した場合に何も反応しないような挙動となってしまいます。ユーザーの操作を「認識はしているけど表示上は何も変化しない」挙動を起こすと、ユーザーとしては「押していないんじゃないか」と不安をいだいたりして、ユーザー体験を損ねてしまいます。
対策
「入力を受け付ける」→「自動変換」というプロセスがわかりやすくなるようにするために、変換はonBlur
まで遅らせてしまうのもいいでしょう。入力が終わってフォーカスを移せば、値が変換されます。Reactで再現するには、本来の値データ以外に「入力中の仮の値」を入れるためのデータ領域が必要となります。
class BlurChangingInput extends React.Component{
state = {
value: '',
inputtingValue: null
}
// そのまま入力中の値を格納するだけ
handleChange = e => {
this.setState({inputtingValue: e.target.value});
}
// 値を変換(ハイフンを消す)
// 入力中の値はクリア
handleBlur = () => {
const value = this.state.inputtingValue.replace(/-/g, '');
this.setState({value, inputtingValue: null});
}
render() {
const {inputtingValue, value} = this.state;
const displayValue = inputtingValue == null ? value : inputtingValue;
return(
<input type="text"
value={displayValue}
onChange={this.handleChange}
onBlur={this.handleBlur}
placeholder="ハイフンは自動で消えます"
className="form-control"
/>
);
}
}
なお、inputtingValue == null
としていますが、空文字列も正当な値なので、inputtingValue || value
とした場合にはフォームを空にしようとした瞬間に元の値が復活する、という挙動になってしまいます。
CodePenに上げました
比較のために「その場でハイフンを消す」フォームと「blurで消す」フォームを作ってみました。動きをご自身でも試していただければと思います。