SafariでIME確定時のEnterを上手く制御できなかった話
はじめに
こんにちは!
スペースマーケットでフロントエンドエンジニアをしておりますk___0122です。
今回は、SafariでIME確定時のEnterの制御が上手くいかずハマったのでまとめてみました!
背景
簡単なサンプルを用意しました。
inputに値を入力し、Enterを押した際にstateを更新したいとします。
最初は以下のような実装をしてました。
import React, { useState } from "react";
export default function App() {
const [keywords, setKeywords] = useState([]);
const handleKeydown = (e) => {
if (e.key === "Enter") {
setKeywords([...keywords, e.target.value]);
}
};
return (
<div>
<input onKeyDown={handleKeydown} />
<ul>
{keywords.map((keyword, i) => (
<li key={i}>{keyword}</li>
))}
</ul>
</div>
);
}
ただここで、e.key === 'Enter'
で判定すると、IME確定時のEnterも含まれてしまいます。
試しにやきゅうと入力し、Enterで予測変換の確定をするとsetKeyWordsが発火してしまいます。
制御できる方法はないかと調べてたところ、KeyboardEvent.isComposingなるものを見つけました。
イベントが変換セッションの途中、すなわち compositionstart の後かつ compositionend の前に発行されたことを示す論理値を返します。
isComposingでは文字の変換中はtrueを返し、そうでない場合はfalseを返してくれるそうです。
KeyboardEvent.isComposingを使った実装が以下のようになります。
import React, { useState } from "react";
export default function App() {
const [keywords, setKeywords] = useState([]);
const handleKeydown = (e) => {
if (!e.nativeEvent.isComposing && e.key === "Enter") {
setKeywords([...keywords, e.target.value]);
}
};
return (
<div>
<input onKeyDown={handleKeydown} />
<ul>
{keywords.map((keyword, i) => (
<li key={i}>{keyword}</li>
))}
</ul>
</div>
);
}
Chromeで確認したところ上手くできてそう。
問題
ところが上記の実装だと、SafariでIME確定時のEnterを押すたびに、setKeywordsが走ってしまいます。
ブラウザによって挙動が違うようで、Safariの場合IME確定時のEnterを押した際に、isComposingがfalseになってしまうそうです。
こちらの記事参考になりました🙏
解決策
非推奨ですが、今回はKeyboardEvent.keyCodeを使いました。
普通のEnterはkeyCodeが13に、IME確定のEnterは229になるようです。
KeyboardEvent.keyCodeを使った実装が以下のようになります。
import React, { useState } from "react";
export default function App() {
const [keywords, setKeywords] = useState([]);
const handleKeydown = (e) => {
if (e.keyCode === 13) {
setKeywords([...keywords, e.target.value]);
}
};
return (
<div>
<input onKeyDown={handleKeydown} />
<ul>
{keywords.map((keyword, i) => (
<li key={i}>{keyword}</li>
))}
</ul>
</div>
);
}
これでSafariでも、IME確定時のEnterと普通のEnterを制御できるようになりました!
isComposingの挙動がブラウザで揃って欲しいです・・・
(他にいい方法あればコメントください🙏)
今回のサンプルです。
最後に
スペースマーケットでは、一緒にサービスを成長させていく仲間を探しています。
とりあえずどんなことしているのか聞いてみたいという方も大歓迎です!
ご興味ありましたら是非ご覧ください!
スペースを簡単に貸し借りできるサービス「スペースマーケット」のエンジニアによる公式ブログです。 弊社採用技術スタックはこちら -> whatweuse.dev/company/spacemarket
Discussion