417 文字
2 分

useEffectEventについてのメモ

2024-01-31

イベントとエフェクタの分離が 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]);
}
useEffectEventについてのメモ
https://blog.ohirunewani.com/posts/use-effect-event-memo/
作者
hrdtbs
公開日
2024-01-31
ライセンス
CC BY-NC-SA 4.0