useEvent
2022/5にReact teamによってRFCが出された新しいhooks
useStateなどに並ぶ、Reactに組み込みのhooksになる
polyfillでは不十分なので、組み込みで入れる ref 割と大きめの変更ではあるが、Reactのminor versionで追加する予定 ref event handlerに対して使用することを目的としているので、一旦useEventという名前になっている
あと、頻繁に使われることになるので短い命名のほうがいい
親(Chat)の中で作った関数を、子(SendButton)のpropsとして渡すやつ
code:ts
function Chat() {
// 🟡 Always a different function
const onClick = () => {
sendMessage(text);
};
return <SendButton onClick={onClick} />;
}
Reactを書いていると、めちゃくちゃ遭遇するパターン
この時、onClickはrenderingごとに毎回生成される
useCallbackのdepsに入るobjectが頻繁に変わる場合は、依然として問題となる
useEventはこの問題を解決する
関数内で使用するobjectに変更があっても、関数の再生成を行わない
code:ts
function Chat() {
// 🟡 Always a different function
const onClick = useEvent(() => {
sendMessage(text);
});
return <SendButton onClick={onClick} />;
}
他の例
useEffect内でsocketを管理している例 ref useEffect内でsocketに接続している
depsにthemeがある
themeが変わるたびに、socketが再接続されてしまう
確かに、これuseEventなしでどうやって解決するんだmrsekut.icon
受け取ったものが、普通の関数でも問題ない
このコード例
code:ts
function Chat({ selectedRoom }) {
const onConnected = (connectedRoom) => {..};
const onMessage = (message) => {..};
useRoom(selectedRoom, { onConnected, onMessage });
// ...
}
function useRoom(room, events) {
const onConnected = useEvent(events.onConnected); // ✅ Stable identity
const onMessage = useEvent(events.onMessage); // ✅ Stable identity
// ..
}
useRoomでは、引数のeventsで2つの関数を受け取っている
これらの関数はuseCallbackなどで、stableになっていない
でも、useRoom内でuseEventしてから使えば問題ない
もちろんこれら2つの関数がChat内でuseEventを使っていてもいい
2重のuseEventになるが、問題ない
これはカプセル化が強化されたと言えるmrsekut.icon
実際は、組み込みなのでもっと効率の良いものになるはず
code:ts
function useEvent(handler) {
const handlerRef = useRef(null);
// In a real implementation, this would run before layout effects
useLayoutEffect(() => {
handlerRef.current = handler;
});
return useCallback((...args) => {
// In a real implementation, this would throw if called during render
const fn = handlerRef.current;
return fn(...args);
}, []);
}
useEventにwrapされたevent handlerは、rendering中に呼び出されるとthrowする
rendering中に呼ばれる関数
useCallbackを使うべき
useEventを使うとthrowされる
Not all functions in effect dependencies are events
よくわからん
変化したときに、再renderingして欲しい時
useEffect内で呼ぶ関数をまるごとuseEventに入れちゃうと理想通りの挙動にならない
それはそうmrsekut.icon
現状考えられる欠点と、ソレについてのコメント ref 読んだ感じそんなヤバい欠点でもなさそうmrsekut.icon
どうやって実現している?
useCallbackの実装時にはコレを思いついていなかった?
これだけの説明だったら明らかにuseCallbackよりよいと思うけど何か問題あるの?
useCallback不要になる?
そんなことはない
rendering中に呼ばれる関数などは、useCallbackを使う必要がある
useCallback remains useful for cases where a function is used while rendering. However, it'll probably be deemphasized with time as it won't be needed as often. ref ただし、今後はあまり使われなくはなるだろう
ほぼ全ての関数が、useEventを使うことになるよね
逆に、素のままの関数を定義することってあるのか?
極論言えば、defaultでuseEventになるようにすればいい、みたいになる
ただ、全てそうしたら問題があるので、defaultになんてことはできない
Force React event handlers to always be declared with useEvent. This seems premature at this point. ref 時期尚早