useEffectEventについてのメモ
useEventの後継として提案されているuseEffectEventについてのメモ。
Table of Contents
イベントとエフェクタの分離がuseEffectEventの目的、useEventの後継として提案されている。
2024年1月時点では、experimental、canaryにも入っていない。
https://react.dev/learn/separating-events-from-effects#declaring-an-effect-event
次のようなカスタムフックを考える。
function useChatRoom({ roomId, theme }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on("connected", () => {
showNotification("Connected!", theme);
});
connection.connect();
return () => {
connection.disconnect();
};
}, [roomId, theme]);
}
この例では、themeが切り替わる度にChatRoomへの接続が切れてしまう。ただしthemeはリアクティブな値であるため、依存関係から入れる必要がある。
useEffectEventを使えばリアクティブにしたくないイベントを、エフェクトから分離することが出来る。roomIdの変更によってのみ再接続が行われる。
function useChatRoom({ roomId, theme }) {
const onConnected = useEffectEvent(() => {
showNotification("Connected!", theme);
});
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on("connected", () => {
onConnected();
});
connection.connect();
return () => connection.disconnect();
}, [roomId]);
}
制約
- エフェクト内からのみ呼び出せる。
- 他のコンポーネントやフックには渡せない。
const onTick = useEffectEvent(() => {
callback();
});
// これはダメ
useTimer(onTick)
<Timer
// これはダメ
onTick={onTick}
/>
useEffectEventを利用した例
Callbackが変更されても、intervalがリセットされない。useEffectEventを利用しない場合、callbackが変更された際にintervalがリセットされる。
function useTimer(callback, delay) {
const onTick = useEffectEvent(() => {
callback();
});
useEffect(() => {
const id = setInterval(() => {
onTick();
}, delay);
return () => {
clearInterval(id);
};
}, [delay]);
}
URLが変更されたときのみログを出せる。useEffectEventを利用しない場合、itemsが変更された場合にもログが出てしまう。
function Page({ url }) {
const { items } = useContext(ShoppingCartContext);
const numberOfItems = items.length;
const onVisit = useEffectEvent(visitedUrl => {
logVisit(visitedUrl, numberOfItems);
});
useEffect(() => {
onVisit(url);
}, [url]);
}