@rtcio/react
Version:
A wrapper around the @rtcio/core library for React integration
70 lines • 2.95 kB
JavaScript
import { useContext, useEffect, useRef } from "react";
import { p2pContext } from "../Provider";
import { option } from "@dbidwell94/ts-utils";
/**
* This function will create a typed usePeerListener hook
* which will allow strongly typed event subscriptions
*/
export function createUsePeerListener() {
function usePeerListener(event, callback, onlyPeerId) {
const ctx = useContext(p2pContext);
if (!ctx) {
throw new Error("usePeerListener must be called in a P2PProvider");
}
const { peerIds, peers } = ctx;
const subscribedPeers = useRef(new Map());
const callbackRef = useRef(callback);
useEffect(() => {
callbackRef.current = callback;
}, [callback]);
useEffect(() => {
const subs = subscribedPeers.current;
const currentPeerIds = new Set(peerIds);
// 1. Clean up stale subscriptions.
// This runs for peers that have left OR if the event name has changed.
for (const [peerId, sub] of subs.entries()) {
if (!currentPeerIds.has(peerId) ||
sub.eventName !== event ||
(onlyPeerId && peerId !== onlyPeerId)) {
sub.controller.abort();
subs.delete(peerId);
}
}
const iterable = option
.unknown(onlyPeerId)
.andThen((val) => {
if (peers.current.get(val)) {
return option.some([
val,
peers.current.get(val),
]);
}
return option.none();
})
.map(([peerId, conn]) => new Map([[peerId, conn]]).entries())
.unwrapOr(peers.current.entries());
// 2. Add subscriptions for new peers.
for (const [peerId, peer] of iterable) {
// If a subscription for this peer doesn't already exist, create one.
if (!subs.has(peerId)) {
const controller = new AbortController();
// The handler always calls the latest callback from the ref.
const handler = (...args) => callbackRef.current(peerId, ...args);
peer.on(event, handler, controller.signal);
subs.set(peerId, { eventName: event, controller });
}
}
}, [peerIds, event, onlyPeerId]);
// 3. When component unmounts, clean up all subscriptions
useEffect(() => {
return () => {
for (const [peerId, sub] of subscribedPeers.current.entries()) {
sub.controller.abort();
subscribedPeers.current.delete(peerId);
}
};
}, []);
}
return usePeerListener;
}
//# sourceMappingURL=usePeerListener.js.map