Firefox + SKKでonCompositionStart/Endを使ったReactのinputが正常に動かない
onCompositionEnd直下で直接状態更新を行うとReactの秘孔を突いて壊れてしまうので,Promise.resolve().then(microtask)程度でいいので遅らせてやるといいsetTimeout(fn,0)でちゃんとタスクキューに積んでやらないとだめになってそう 悪化してる,なんで?
??? < 本当に解決しているのか?
TODO: Reactがどうやってキーボードイベントをハンドリングして,どういう死に方をしているのかしらべる textareaだと死なないらしい?(Scrapboxのエディタ部分はtextarea) そんなことはない
code:Scrapboxの検索欄に入力できるようにする.user.js
'use strict';
async function waitFor(selector) {
while(true) {
const el = document.querySelector(selector)
if(el != null) return el
await new Promise(r => requestAnimationFrame(r))
}
}
waitFor('.navbar input.form-control').then(el => {
const seen = new Set()
el.addEventListener('compositionend', ev => {
if(seen.has(ev)) return
ev.stopPropagation()
seen.add(ev)
Promise.resolve().then(() => {
el.dispatchEvent(ev)
setTimeout(() => {
seen.delete(ev)
}, 1000)
})
}, { capture: true })
})
ほんの僅かだけ遅らせて再送出するようにしている
きっかけ
実は正常動作してない.確定時に▼が残る
https://tweet-card.now.sh/1395677454736388097.png?lang=ja&theme=dark https://twitter.com/rokoucha/status/1395677454736388097
おそらくSKK特有のキーボードイベントの送出パターンがあって,それがうまく動いてない なんでやって思って検索ボックスの実装を見ると,composition{start,end}が使われている.ScrapboxはReactを使っているので,Reactを使って同等のコードを書いてみる. なんかガチャガチャやってたらonCompositionUpdate={onCompositionEnd}のときだけうまく動く
話がデカくなってきた
rokoucha.icon < これほとんど同じじゃね?
ChromeやFirefoxなどの特定のブラウザを特別扱いするコードは,IE8,9以外には特になかった
なんとなく思いついて,refを使ってuseEffect内で直接composition{start,end}を購読して,onComposition{Start,End}でやってる処理をやってみた→入力できないまま
もしかして更新が悪い?って思ってその中でやってる状態更新を止めると入力できるようになった
Firefoxの実装の関係で,Reactの秘孔を突くタイミングでcompositionendが来てしまってるみたい
とりあえずstopPropagationしてみる
→ちゃんと動く
onCompositionUpdate={onCompositionEnd}でちゃんと動いたのは,compositionendでの状態更新が再レンダーを引き起こさなかったから rokoucha.iconがイベントの並びは同じだと調べてくれたのもよかった.問題なのはイベントの並びじゃなくてタイミングなのだと気付けた