import { useCallback, useEffect, useRef } from 'react'; // A lifetime for work begun in one scope. It ends, in the render that sees the change, whenever the scope // changes - and a return to the same scope is a new lifetime, so work begun before can never resume as if // current. It also ends while the consumer is unmounted. isLive answers from refs, so a callback held across // an await asks about now, not about then. export const useScopeLifetime = (scope: string): { generation: number; isLive: (generation: number) => boolean } => { const lifetime = useRef({ scope, generation: 0 }); const mounted = useRef(true); if (lifetime.current.scope !== scope) lifetime.current = { scope, generation: lifetime.current.generation + 1 }; useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []); const isLive = useCallback((generation: number) => mounted.current && lifetime.current.generation === generation, []); return { generation: lifetime.current.generation, isLive }; };