optimize: VueUse を用いてグローバルなイベント監視を効率化する#4890
Conversation
|
Preview (prod) → https://4890-prod.traq-preview.trapti.tech/ |
window に対するイベント監視を、参照カウントと Effect Scope を用いて効率化するwindow に対するイベント監視を効率化する
window に対するイベント監視を効率化する
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #4890 +/- ##
==========================================
- Coverage 61.01% 60.81% -0.20%
==========================================
Files 101 101
Lines 2970 2973 +3
Branches 615 616 +1
==========================================
- Hits 1812 1808 -4
- Misses 1061 1071 +10
+ Partials 97 94 -3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
9a99922 to
7d77bf9
Compare
14fa6b5 to
3dd0f11
Compare
3dd0f11 to
62ec88b
Compare
62ec88b to
72295bf
Compare
64e6323 to
18dcfc4
Compare
- refactor: `MouseEvent` と `TouchEvent` を併用している部分を `PointerEvent` に統合する
18dcfc4 to
03cee1d
Compare
03cee1d to
142c21a
Compare
b1908ed to
bcd48e0
Compare
10e8153 to
68df132
Compare
… optimize/effect-scope
… optimize/effect-scope
68df132 to
a061e98
Compare
cp-20
left a comment
There was a problem hiding this comment.
ありがとう
いくつかコメントしたけど、概ね良いと思います
| // eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
| return state! |
There was a problem hiding this comment.
non-null というよりは as ReturnType<Fn> な気がしたけど、どうだろう (Fn に何が入るのか分からない以上 null が返ってくるかもしれない)
src/lib/dom/unrefElement.ts
Outdated
| export function unrefElement<T>( | ||
| element: MaybeRefOrGetter<T> | ||
| ): UnrefElementReturn<T> |
There was a problem hiding this comment.
シグネチャを分けてる意味ある? (関数オーバーロード?)
There was a problem hiding this comment.
だいぶ前に書いた部分なので忘れてしまったのですが、たぶんない気がしたので直します
| _targets: MaybeRefOrGetter<MaybeArray<Target> | null | undefined>, | ||
| _events: MaybeRefOrGetter<MaybeArray<EventNames<Target>>>, | ||
| _handlers: MaybeRef<MaybeArray<EventListenerType<EventType>>>, | ||
| options?: MaybeRefOrGetter<boolean | AddEventListenerOptions> |
There was a problem hiding this comment.
_ の prefix をつけるより argment であることを示した方が良いかも (_ の prefix は未使用変数に付けるのが慣例的な気がしている)
src/composables/useResponsive.ts
Outdated
| import useEventListener from './dom/useEventListener' | ||
|
|
||
| const useResponsive = () => { | ||
| const queryList = window.matchMedia(`(max-width: ${mobileMinBreakpoint}px)`) |
There was a problem hiding this comment.
この変更の本質ではないけど、なんで queryList って命名なんだろう
There was a problem hiding this comment.
ここは過去のコードから引き継いだ部分なので定かではないのですが、window.matchMedia が返すのが MediaQueryList だからな気がします
| _targets: MaybeRefOrGetter<MaybeArray<Target> | null | undefined>, | ||
| _events: MaybeRefOrGetter<MaybeArray<EventNames<Target>>>, | ||
| _handlers: MaybeRef<MaybeArray<EventListenerType<EventType>>>, |
There was a problem hiding this comment.
これらが MaybeArray を受け取るのはなんでですか? (見た感じ array で受け取っている箇所はなさそう?)
There was a problem hiding this comment.
VueUse の useEventListener が MaybeArray を受け付けていたので、使用感がそろっていたほうが嬉しいかと思ってそのようにしました。
There was a problem hiding this comment.
なるほど、、、 合わせても良いけど、実装が複雑になるし実際使うことはほぼない気がするから (配列にするときはその分だけ useEventListener を呼び出せばよい) 配列を受け取らなくても良い気がするな
There was a problem hiding this comment.
確かにです、そうします
(と思ったのですがそもそも VueUse を導入してしまってもよさそう....?)
There was a problem hiding this comment.
わざわざこっちでメンテナンスする理由が特に思い浮かばないのと、他にも VueUse で置換できそうな部分があったので VueUse を導入しました
| // eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
| containerEle.value!.addEventListener( | ||
| 'mouseup', | ||
| _upEvent => { | ||
| // eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
| containerEle.value!.removeEventListener('mousemove', moveUpdate) | ||
| const stop = useEventListener( | ||
| containerEle, | ||
| 'mousemove', | ||
| (moveEvent: MouseEvent) => { | ||
| stop() | ||
| moveUpdate(moveEvent) | ||
| }, | ||
| { once: true } | ||
| { | ||
| once: true | ||
| } | ||
| ) |
| const startEventName = isIOS() ? 'touchstart' : 'mousedown' | ||
| const endEventName = isIOS() ? 'touchend' : 'mouseup' |
src/lib/dom/unrefElement.ts
Outdated
| return isObjectAndHasKey(plain, '$el') ? plain.$el : plain | ||
| return ( | ||
| isObjectAndHasKey(plain, '$el') ? plain.$el : plain | ||
| ) as UnrefElementReturn<T> |
There was a problem hiding this comment.
アサーションいらないんじゃない? (普通にアノテーションするだけで十分)
There was a problem hiding this comment.
その後 VueUse の unrefElement を利用するように書き換えたんですが、戻り値の型 (HTMLElement | SVGElement | undefined | null) がちょっと微妙だった (.$el の型を infer してほしかった) のでアサーションする形になってしまいました
https://github.com/traPtitech/traQ_S-UI/pull/4890/changes#diff-ad8f25153aa059247c28efc0e1a4b6aaae7d0020fea996985c41c9330ffa341a
There was a problem hiding this comment.
微妙なのでアサーションするのは TypeScript の型安全性を破壊する行為なので非常に良くないです その型が気に食わないなら気に食わない部分を自分でハンドリングする必要があるはずです (型には意味があるはずなので)
There was a problem hiding this comment.
色々試した結果結局このような形にすることしかできなかったのですが、この as any を外すことってできるんでしょうか....?(関数オーバーロードも実質的には型アサーションと変わりないですよね)
export function unrefElement<T>(
element: MaybeRefOrGetter<T>
): T extends { $el: infer E } ? E : T {
const plain = toValue(element)
if (isObjectAndHasKey(plain, '$el')) return plain.$el as any
return plain as any
}There was a problem hiding this comment.
最後の as any はいらないと思うけど、2行目のやつは外すの難しいかも
There was a problem hiding this comment.
どっちを外しても Type *** is not assignable to type 'T extends { $el: infer E; } ? E : T' と言われてしまって困ってます
There was a problem hiding this comment.
as any するぐらいなら最初からアサーションした方がましだったかも すいません
There was a problem hiding this comment.
やっぱり無理そうだったので諦めました :komata-nya:
6c3dc38 to
262d84b
Compare
262d84b to
c0cf29d
Compare
なぜこの PR を入れたいのか
onBeforeUnloadみたいなのをもっと楽に書きたい動作確認の手順
PR を出す前の確認事項