はじめに
こんにちは。久しぶりに投稿させていただきます。今回もReact Nativeの開発ノウハウです。
「この入力欄には数字のみ受け付けてほしい」
こういう要望、よくあるではないか。
React NativeのTextInput
では入力タイプが設定できないが、下記のように実装してたら、入力制限もできる。
<TextInput
onChangeText={t => setText(t.replace(/[^0-9]/g, ""))}
value={text}
/>
……けれども、Windows環境で、日本語IMEで入力すると、問題が起きる。
問題点
問題というのは、TextInput
にすでに何か入力していた場合、日本語IMEで何かを入力しようとすると(もちろん、日本語を受け付けないようにしている)、既存の文字が消去される。
Expo Snackで動作を見ましょう。
上記のようにTextInput
を実装していたら、数字だけ受け付けることになる。
次に日本語IMEで「あいうえお」を入力してみる。「あ」と「い」を押したら、かなが出てこないが、入力欄の「0」が消えた。
つづいて「お」まで押したら、すべての数字が消えた。
この問題は、Windowsに起きるけど、Android/iOSには起きない。ちなみに、ほかの日本語IMEや中国語IMEでも問題が起きる(Google日本語IME・Microsoft中国語IMEで検証済み)。
解決策
なぜこうなるかわからないけど、IMEが原因だとなんとなく理解しているだろう。では解決するにも、IMEに何とかすることですね。
W3Cはたくさんのキーボード押すイベントを定義している。そのうち、IME入力も含んでいる。
https://www.w3.org/TR/uievents-key/#keys-composition
React Native TextInput
では、上記の一部を利用していて、キーボード押すイベント(onKeyPress
)に入っている。そして、onKeyPress
の発火タイミングはonChangeText
より先。そこで、onKeyPress
でIME入力かどうかを判別し、YESの場合、IME入力自体を無視すれば、問題回避できるだろう。
ではさっそくやってみましょう。
<TextInput
onKeyPress={e => {
isIme = e.key == "Process"; //IMEで入力する時、値は常に"Process"
}}
onChangeText={t => {
if (!isIme) setText(t.replace(/[^0-9]/g, ""));
}}
value={text}
/>
このように実装していれば、既存の文字が消去される問題が回避できる。
「あいうえおかきくけこ」まで押しても、数字たちが消去されていない。
最後に
この記事はあくまでも私個人の経験です。間違っているところ、もっと良い方法がございましたら、ぜひ教えてください。
参考資料
https://stackoverflow.com/questions/32946793/react-native-textinput-that-only-accepts-numeric-characters
https://www.w3.org/TR/uievents-key/#keys-composition