( allNodes: GraphNode[], allLinks: GraphLink[], layoutConfig: LayoutConfig, enabled: boolean = true, )
| 41 | * and brief loss of community colouring. |
| 42 | */ |
| 43 | export function useCommunities( |
| 44 | allNodes: GraphNode[], |
| 45 | allLinks: GraphLink[], |
| 46 | layoutConfig: LayoutConfig, |
| 47 | enabled: boolean = true, |
| 48 | ): CommunityData { |
| 49 | const [communityData, setCommunityData] = |
| 50 | useState<CommunityData>(EMPTY_COMMUNITY); |
| 51 | const workerRef = useRef<Worker | null>(null); |
| 52 | const requestIdRef = useRef(0); |
| 53 | const unmountedRef = useRef(false); |
| 54 | |
| 55 | useEffect(() => { |
| 56 | unmountedRef.current = false; |
| 57 | return () => { |
| 58 | unmountedRef.current = true; |
| 59 | workerRef.current?.terminate(); |
| 60 | workerRef.current = null; |
| 61 | }; |
| 62 | }, []); |
| 63 | |
| 64 | useEffect(() => { |
| 65 | // Master switch: when communities are disabled, never spawn the |
| 66 | // Louvain worker and keep assignments empty. Downstream features |
| 67 | // (colors, labels, community-gravity force, 3D depth) already treat |
| 68 | // empty assignments as "no communities" — flipping this off cleanly |
| 69 | // returns to a community-agnostic view with no wasted compute. |
| 70 | if (!enabled) { |
| 71 | // eslint-disable-next-line react-hooks/set-state-in-effect -- reset to empty when disabled |
| 72 | setCommunityData(EMPTY_COMMUNITY); |
| 73 | workerRef.current?.terminate(); |
| 74 | workerRef.current = null; |
| 75 | return; |
| 76 | } |
| 77 | if (allNodes.length === 0) { |
| 78 | setCommunityData(EMPTY_COMMUNITY); |
| 79 | return; |
| 80 | } |
| 81 | |
| 82 | // Terminate previous worker |
| 83 | workerRef.current?.terminate(); |
| 84 | workerRef.current = null; |
| 85 | |
| 86 | const reqId = ++requestIdRef.current; |
| 87 | |
| 88 | const worker = new Worker( |
| 89 | new URL('../workers/communityWorker.ts', import.meta.url), |
| 90 | { type: 'module' }, |
| 91 | ); |
| 92 | workerRef.current = worker; |
| 93 | |
| 94 | worker.onerror = (err) => { |
| 95 | if (reqId !== requestIdRef.current || unmountedRef.current) return; |
| 96 | console.error('[graph] community worker failed:', err); |
| 97 | setCommunityData(EMPTY_COMMUNITY); |
| 98 | }; |
| 99 | |
| 100 | worker.onmessage = (e: MessageEvent<CommunityResponse>) => { |
no test coverage detected