Join Nostr
2026-09-25 01:21:21 UTC

8020 on Nostr: Alex Gleason ditto.pub seems to have an infinite loop bug in `useAuthors`. I noticed ...

ditto.pub seems to have an infinite loop bug in `useAuthors`. I noticed because my CPU fan was spinning up when nothing much else was running. I profiled it and asked my clanker to figure it out:

==================

**Ditto appears to have a continuous React → database → React feedback loop in its `useAuthors` hook.** That’s the main repeated work in this profile.

Across the **9.38-second capture**:

| Work | Measured activity |
|---|---:|
| Ditto’s main page thread | **8.10 seconds of CPU — 86% of one core** |
| Timer callbacks traced to `useAuthors` cache updates | **2,461 — about 262/second** |
| Time inside those callbacks, including resulting work | **6.61 seconds** |
| IndexedDB `success` events | **2,461** |

The load stays high throughout the capture, so this isn’t just a brief startup spike.

I fetched the exact JavaScript bundle named in your profile. The [deployed `useAuthors` code](https://ditto.pub/assets/useAuthors-jBNN03G9.js) does this:

1. Each render creates a **fresh array** of sorted, unique author IDs.
2. That array is in a `useEffect` dependency list. Its identity changes every render, even when the authors haven’t changed.
3. The effect queries IndexedDB for those authors’ profiles.
4. It writes a **new `Map`** into the `["authors", …]` query cache, even when the profiles are unchanged.
5. The cache update causes another render, restarting the cycle.

The profile directly connects those cache writes to the query library’s zero-delay timer scheduler, followed by substantial React rendering work. Its roughly matching timer and database event counts strongly support this diagnosis. The hook’s five-minute `staleTime` doesn’t prevent this: the repeated reads happen in a separate effect.

**The developer fix:** make that effect depend on the *contents* of the author list rather than a newly allocated array, and preserve the existing cached `Map` when nothing changed. Both would break the unnecessary update cycle.