前提・実現したいこと
Reactでテキスト編集を含むアプリケーションを開発しています。textareaでテキストの折り返しを可能にしつつ、Enterキー押下時に改行をキャンセルしblurする仕様を実装しようとし、以下のコンポーネントを作成しました。
javascript
1import React, { useState } from 'react' 2 3export const App = () => { 4 const [value, setValue] = useState('') 5 const [isComposing, setIsComposing] = useState(false) 6 7 const handleKeyDown = e => { 8 // isComposingがtrue(IME変換中)の時は変換確定のためにEnterキーを受け付ける 9 if (!isComposing && e.code === 'Enter') { 10 e.preventDefault() 11 e.currentTarget.blur() 12 } 13 } 14 15 const handleChange = e => { 16 // テキストペースト時は改行を半角スペースに変換する 17 setValue(e.target.value.replace(/\n/g, ' ')) 18 } 19 20 return ( 21 <div> 22 <textarea 23 value={value} 24 onChange={handleChange} 25 onKeyDown={handleKeyDown} 26 onCompositionStart={() => setIsComposing(true)} 27 onCompositionEnd={() => setIsComposing(false)} 28 /> 29 </div> 30 ) 31}
発生している問題
上記コンポーネントのtextareaに日本語を入力し、入力を確定せずにBackspaceで消していくと、最後の文字(入力時の最初の文字)が消えずに残ります。Firefoxで発生したもののChromeでは再現せず、Firefoxのバグの可能性もあると思うのですが、これを回避する方法は何かありますでしょうか?
問題を再現できる最小(と思われる)コード
javascript
1import React, { useState } from 'react' 2 3export const App = () => { 4 const [value, setValue] = useState('') 5 const [state, setState] = useState(false) 6 7 return ( 8 <div> 9 <textarea 10 value={value} 11 onChange={e => setValue(e.target.value)} 12 onCompositionEnd={() => setState(state => !state)} 13 /> 14 </div> 15 ) 16}
わかっていること
- macOS Big Sur 11.5.2、React 17.0.0にて、Firefox 91.0.2で問題が発生し、Google Chrome 92.0.4515.159で問題が発生しないことを確認しています
- 上記コードの
textarea
をinput
にしても再現します - 上記最小コードの9行目
value={value}
を削除すると問題は発生しません - 上記最小コードの11行目を、削除する or
onCompositionEnd={() => {}}
とする oronCompositionEnd={() => console.log('test')}
とする oronCompositionEnd={() => setState(false)}
とすると、問題は発生しません - 上記最小コードの11行目を
onCompositionEnd={() => setState(true)}
とすると、最初のIME入力終了時のみ問題が発生します - compositionendイベント発火時にstateが変化しなければ問題は発生しないようです
あなたの回答
tips
プレビュー