/** * @file keepIfSame.ts * @description State-updater helper for polled data: keeps the previous value's * identity when the freshly fetched payload is value-identical, so a background * poll that found nothing new does not re-render the tree it feeds. * * Every poller in this app (`api.lanes.list`, `api.run.list`, `api.lanes.git`, * …) returns a brand-new object graph on each tick. Passing that straight into * `setState` re-renders every consumer several times a minute even when the * dashboard is completely idle — visible as the whole page "refreshing". * * @author Nguyễn Ngọc Trí Vĩ */ /** * Wraps a freshly fetched value as a functional state update that returns the * previous state unchanged when the two are value-equal. * * Usage: `setLanes(keepIfSame(r.lanes))` instead of `setLanes(r.lanes)`. * * `prev` is typed wider than `T` so the same helper works for the `T | null` * states the pollers start out in; the cast is sound because it only happens on * the branch where `prev` serializes identically to `next`. * * @param next The value just fetched. * @returns An updater for `setState`, yielding `prev` when nothing changed. */ export function keepIfSame(next: T): (prev: T | null | undefined) => T { // ponytail: JSON.stringify comparison — fine for the payloads this app polls // (lane lists, run lists, a git-facts object: tens of small records, key order // is stable because it comes from the same serializer every time). Swap for a // structural deep-equal if a poller ever returns something big or key-unstable. return (prev) => (JSON.stringify(prev) === JSON.stringify(next) ? (prev as T) : next); }